1 {*********************************************************}
3 { Zeos Database Objects }
4 { PostgreSQL Database Connectivity Classes }
6 { Originally written by Sergey Seroukhov }
7 { and Sergey Merkuriev }
9 {*********************************************************}
11 {@********************************************************}
12 { Copyright (c) 1999-2012 Zeos Development Group }
14 { License Agreement: }
16 { This library is distributed in the hope that it will be }
17 { useful, but WITHOUT ANY WARRANTY; without even the }
18 { implied warranty of MERCHANTABILITY or FITNESS FOR }
19 { A PARTICULAR PURPOSE. See the GNU Lesser General }
20 { Public License for more details. }
22 { The source code of the ZEOS Libraries and packages are }
23 { distributed under the Library GNU General Public }
24 { License (see the file COPYING / COPYING.ZEOS) }
25 { with the following modification: }
26 { As a special exception, the copyright holders of this }
27 { library give you permission to link this library with }
28 { independent modules to produce an executable, }
29 { regardless of the license terms of these independent }
30 { modules, and to copy and distribute the resulting }
31 { executable under terms of your choice, provided that }
32 { you also meet, for each linked independent module, }
33 { the terms and conditions of the license of that module. }
34 { An independent module is a module which is not derived }
35 { from or based on this library. If you modify this }
36 { library, you may extend this exception to your version }
37 { of the library, but you are not obligated to do so. }
38 { If you do not wish to do so, delete this exception }
39 { statement from your version. }
42 { The project web site is located on: }
43 { http://zeos.firmos.at (FORUM) }
44 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
45 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
47 { http://www.sourceforge.net/projects/zeoslib. }
50 { Zeos Development Group. }
51 {********************************************************@}
53 unit ZDbcPostgreSqlMetadata;
60 Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
61 ZSysUtils, ZDbcIntfs, ZDbcMetadata, ZCompatibility, ZDbcPostgreSqlUtils,
62 ZDbcConnection, ZSelectSchema;
65 {** Implements a PostgreSQL Case Sensitive/Unsensitive identifier convertor. }
66 TZPostgreSQLIdentifierConvertor = class (TZDefaultIdentifierConvertor)
68 function IsSpecialCase(const Value: string): Boolean; override;
70 function IsQuoted(const Value: string): Boolean; override;
71 function Quote(const Value: string): string; override;
72 function ExtractQuote(const Value: string): string; override;
76 Database information interface for PostgreSQL. Adds some PostgreSQL-specific
77 methods to IZDatabaseInfo.
78 } // technobot 2008-06-27
79 IZPostgreSQLDatabaseInfo = interface(IZDatabaseInfo)
80 ['{7D48BBAA-FAE2-48EA-8B9E-663CCA5690EC}']
81 // database and driver info:
82 function HasMinimumServerVersion(MajorVersion: Integer;
83 MinorVersion: Integer): Boolean;
85 IZPostgreDBInfo = IZPostgreSQLDatabaseInfo; // shorthand alias
87 // technobot 2008-06-27 - methods moved as is from TZPostgreSQLDatabaseMetadata:
88 {** Implements PostgreSQL Database Information. }
89 TZPostgreSQLDatabaseInfo = class(TZAbstractDatabaseInfo, IZPostgreSQLDatabaseInfo)
91 function GetMaxIndexKeys: Integer;
92 function GetMaxNameLength: Integer;
93 // function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string;
94 // const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override;
96 constructor Create(const Metadata: TZAbstractDatabaseMetadata);
97 destructor Destroy; override;
99 // database/driver/server info:
100 function GetDatabaseProductName: string; override;
101 function GetDatabaseProductVersion: string; override;
102 function GetDriverName: string; override;
103 // function GetDriverVersion: string; override; -> Same as parent
104 function GetDriverMajorVersion: Integer; override;
105 function GetDriverMinorVersion: Integer; override;
106 function GetServerVersion: string; override;
107 function HasMinimumServerVersion(MajorVersion: Integer;
108 MinorVersion: Integer): Boolean; // was TZPostgreSQLDatabaseMetadata.HaveMinimumServerVersion
110 // capabilities (what it can/cannot do):
111 // function AllProceduresAreCallable: Boolean; override; -> Not implemented
112 // function AllTablesAreSelectable: Boolean; override; -> Not implemented
113 function SupportsMixedCaseIdentifiers: Boolean; override;
114 function SupportsMixedCaseQuotedIdentifiers: Boolean; override;
115 // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented
116 // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented
117 // function SupportsColumnAliasing: Boolean; override; -> Not implemented
118 // function SupportsConvert: Boolean; override; -> Not implemented
119 // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType):
120 // Boolean; override; -> Not implemented
121 // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented
122 // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented
123 function SupportsExpressionsInOrderBy: Boolean; override;
124 function SupportsOrderByUnrelated: Boolean; override;
125 function SupportsGroupBy: Boolean; override;
126 function SupportsGroupByUnrelated: Boolean; override;
127 function SupportsGroupByBeyondSelect: Boolean; override;
128 // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented
129 // function SupportsMultipleResultSets: Boolean; override; -> Not implemented
130 // function SupportsMultipleTransactions: Boolean; override; -> Not implemented
131 // function SupportsNonNullableColumns: Boolean; override; -> Not implemented
132 // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented
133 // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented
134 // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented
135 // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented
136 // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented
137 // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented
138 function SupportsIntegrityEnhancementFacility: Boolean; override;
139 // function SupportsOuterJoins: Boolean; override; -> Not implemented
140 // function SupportsFullOuterJoins: Boolean; override; -> Not implemented
141 // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented
142 function SupportsSchemasInDataManipulation: Boolean; override;
143 function SupportsSchemasInProcedureCalls: Boolean; override;
144 function SupportsSchemasInTableDefinitions: Boolean; override;
145 function SupportsSchemasInIndexDefinitions: Boolean; override;
146 function SupportsSchemasInPrivilegeDefinitions: Boolean; override;
147 function SupportsCatalogsInDataManipulation: Boolean; override;
148 function SupportsCatalogsInProcedureCalls: Boolean; override;
149 function SupportsCatalogsInTableDefinitions: Boolean; override;
150 function SupportsCatalogsInIndexDefinitions: Boolean; override;
151 function SupportsCatalogsInPrivilegeDefinitions: Boolean; override;
152 function SupportsPositionedDelete: Boolean; override;
153 function SupportsPositionedUpdate: Boolean; override;
154 function SupportsSelectForUpdate: Boolean; override;
155 function SupportsStoredProcedures: Boolean; override;
156 function SupportsSubqueriesInComparisons: Boolean; override;
157 function SupportsSubqueriesInExists: Boolean; override;
158 function SupportsSubqueriesInIns: Boolean; override;
159 function SupportsSubqueriesInQuantifieds: Boolean; override;
160 function SupportsCorrelatedSubqueries: Boolean; override;
161 function SupportsUnion: Boolean; override;
162 function SupportsUnionAll: Boolean; override;
163 function SupportsOpenCursorsAcrossCommit: Boolean; override;
164 function SupportsOpenCursorsAcrossRollback: Boolean; override;
165 function SupportsOpenStatementsAcrossCommit: Boolean; override;
166 function SupportsOpenStatementsAcrossRollback: Boolean; override;
167 function SupportsTransactions: Boolean; override;
168 function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel):
170 function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override;
171 function SupportsDataManipulationTransactionsOnly: Boolean; override;
172 function SupportsResultSetType(_Type: TZResultSetType): Boolean; override;
173 function SupportsResultSetConcurrency(_Type: TZResultSetType;
174 Concurrency: TZResultSetConcurrency): Boolean; override;
175 // function SupportsBatchUpdates: Boolean; override; -> Not implemented
178 function GetMaxBinaryLiteralLength: Integer; override;
179 function GetMaxCharLiteralLength: Integer; override;
180 function GetMaxColumnNameLength: Integer; override;
181 function GetMaxColumnsInGroupBy: Integer; override;
182 function GetMaxColumnsInIndex: Integer; override;
183 function GetMaxColumnsInOrderBy: Integer; override;
184 function GetMaxColumnsInSelect: Integer; override;
185 function GetMaxColumnsInTable: Integer; override;
186 function GetMaxConnections: Integer; override;
187 function GetMaxCursorNameLength: Integer; override;
188 function GetMaxIndexLength: Integer; override;
189 function GetMaxSchemaNameLength: Integer; override;
190 function GetMaxProcedureNameLength: Integer; override;
191 function GetMaxCatalogNameLength: Integer; override;
192 function GetMaxRowSize: Integer; override;
193 function GetMaxStatementLength: Integer; override;
194 function GetMaxStatements: Integer; override;
195 function GetMaxTableNameLength: Integer; override;
196 function GetMaxTablesInSelect: Integer; override;
197 function GetMaxUserNameLength: Integer; override;
199 // policies (how are various data and operations handled):
200 // function IsReadOnly: Boolean; override; -> Not implemented
201 // function IsCatalogAtStart: Boolean; override; -> Not implemented
202 function DoesMaxRowSizeIncludeBlobs: Boolean; override;
203 // function NullsAreSortedHigh: Boolean; override; -> Not implemented
204 // function NullsAreSortedLow: Boolean; override; -> Not implemented
205 // function NullsAreSortedAtStart: Boolean; override; -> Not implemented
206 // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented
207 // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented
208 // function UsesLocalFiles: Boolean; override; -> Not implemented
209 function UsesLocalFilePerTable: Boolean; override;
210 function StoresUpperCaseIdentifiers: Boolean; override;
211 function StoresLowerCaseIdentifiers: Boolean; override;
212 function StoresMixedCaseIdentifiers: Boolean; override;
213 function StoresUpperCaseQuotedIdentifiers: Boolean; override;
214 function StoresLowerCaseQuotedIdentifiers: Boolean; override;
215 function StoresMixedCaseQuotedIdentifiers: Boolean; override;
216 function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override;
217 function DataDefinitionCausesTransactionCommit: Boolean; override;
218 function DataDefinitionIgnoredInTransactions: Boolean; override;
220 // interface details (terms, keywords, etc):
221 function GetSchemaTerm: string; override;
222 function GetProcedureTerm: string; override;
223 function GetCatalogTerm: string; override;
224 function GetCatalogSeparator: string; override;
225 function GetSQLKeywords: string; override;
226 function GetNumericFunctions: string; override;
227 function GetStringFunctions: string; override;
228 function GetSystemFunctions: string; override;
229 function GetTimeDateFunctions: string; override;
230 function GetSearchStringEscape: string; override;
231 function GetExtraNameCharacters: string; override;
234 {** Implements PostgreSQL Database Metadata. }
235 TZPostgreSQLDatabaseMetadata = class(TZAbstractDatabaseMetadata)
237 function GetRuleType(const Rule: String): TZImportedKey;
239 function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-27
241 // (technobot) should any of these be moved to TZPostgreSQLDatabaseInfo?:
242 function GetPostgreSQLType(Oid: Integer): string;
243 function GetSQLTypeByOid(Oid: Integer): TZSQLType;
244 function GetSQLTypeByName(TypeName: string): TZSQLType;
245 function TableTypeSQLExpression(TableType: string; UseSchemas: Boolean):
247 procedure ParseACLArray(List: TStrings; AclString: string);
248 function GetPrivilegeName(Permission: char): string;
249 // (technobot) end of questioned section
251 function EscapeString(const S: string): string; override;
252 function UncachedGetTables(const Catalog: string; const SchemaPattern: string;
253 const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override;
254 function UncachedGetSchemas: IZResultSet; override;
255 function UncachedGetCatalogs: IZResultSet; override;
256 function UncachedGetTableTypes: IZResultSet; override;
257 function UncachedGetColumns(const Catalog: string; const SchemaPattern: string;
258 const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override;
259 function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string;
260 const TableNamePattern: string): IZResultSet; override;
261 function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string;
262 const Table: string; const ColumnNamePattern: string): IZResultSet; override;
263 function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string;
264 const Table: string): IZResultSet; override;
265 function UncachedGetImportedKeys(const Catalog: string; const Schema: string;
266 const Table: string): IZResultSet; override;
267 function UncachedGetExportedKeys(const Catalog: string; const Schema: string;
268 const Table: string): IZResultSet; override;
269 function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string;
270 const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string;
271 const ForeignTable: string): IZResultSet; override;
272 function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string;
273 Unique: Boolean; Approximate: Boolean): IZResultSet; override;
274 function UncachedGetSequences(const Catalog: string; const SchemaPattern: string;
275 const SequenceNamePattern: string): IZResultSet; override;
276 function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string;
277 const ProcedureNamePattern: string): IZResultSet; override;
278 function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string;
279 const ProcedureNamePattern: string; const ColumnNamePattern: string):
280 IZResultSet; override;
281 function UncachedGetVersionColumns(const Catalog: string; const Schema: string;
282 const Table: string): IZResultSet; override;
283 function UncachedGetTypeInfo: IZResultSet; override;
284 function UncachedGetCharacterSets: IZResultSet; override; //EgonHugeist
287 destructor Destroy; override;
288 function GetIdentifierConvertor: IZIdentifierConvertor; override;
294 ZMessages, ZDbcUtils, ZDbcPostgreSql;
296 { TZPostgreSQLDatabaseInfo }
299 Constructs this object.
300 @param Metadata the interface of the correpsonding database metadata object
302 constructor TZPostgreSQLDatabaseInfo.Create(const Metadata: TZAbstractDatabaseMetadata);
308 Destroys this object and cleanups the memory.
310 destructor TZPostgreSQLDatabaseInfo.Destroy;
315 //----------------------------------------------------------------------
316 // First, a variety of minor information about the target database.
319 What's the name of this database product?
320 @return database product name
322 function TZPostgreSQLDatabaseInfo.GetDatabaseProductName: string;
324 Result := 'PostgreSQL';
328 What's the version of this database product?
329 @return database version
331 function TZPostgreSQLDatabaseInfo.GetDatabaseProductVersion: string;
337 What's the name of this JDBC driver?
338 @return JDBC driver name
340 function TZPostgreSQLDatabaseInfo.GetDriverName: string;
342 Result := 'Zeos Database Connectivity Driver for PostgreSQL';
346 What's this JDBC driver's major version number?
347 @return JDBC driver major version
349 function TZPostgreSQLDatabaseInfo.GetDriverMajorVersion: Integer;
355 What's this JDBC driver's minor version number?
356 @return JDBC driver minor version number
358 function TZPostgreSQLDatabaseInfo.GetDriverMinorVersion: Integer;
364 Returns the server version
365 @return the server version string
367 function TZPostgreSQLDatabaseInfo.GetServerVersion: string;
369 with Metadata.GetConnection as IZPostgreSQLConnection do
370 Result := Format('%s.%s', [GetServerMajorVersion, GetServerMinorVersion]);
374 Does the database use a file for each table?
375 @return true if the database uses a local file for each table
377 function TZPostgreSQLDatabaseInfo.UsesLocalFilePerTable: Boolean;
383 Does the database treat mixed case unquoted SQL identifiers as
384 case sensitive and as a result store them in mixed case?
385 A JDBC Compliant<sup><font size=-2>TM</font></sup> driver will always return false.
386 @return <code>true</code> if so; <code>false</code> otherwise
388 function TZPostgreSQLDatabaseInfo.SupportsMixedCaseIdentifiers: Boolean;
394 Does the database treat mixed case unquoted SQL identifiers as
395 case insensitive and store them in upper case?
396 @return <code>true</code> if so; <code>false</code> otherwise
398 function TZPostgreSQLDatabaseInfo.StoresUpperCaseIdentifiers: Boolean;
404 Does the database treat mixed case unquoted SQL identifiers as
405 case insensitive and store them in lower case?
406 @return <code>true</code> if so; <code>false</code> otherwise
408 function TZPostgreSQLDatabaseInfo.StoresLowerCaseIdentifiers: Boolean;
414 Does the database treat mixed case unquoted SQL identifiers as
415 case insensitive and store them in mixed case?
416 @return <code>true</code> if so; <code>false</code> otherwise
418 function TZPostgreSQLDatabaseInfo.StoresMixedCaseIdentifiers: Boolean;
424 Does the database treat mixed case quoted SQL identifiers as
425 case sensitive and as a result store them in mixed case?
426 A JDBC Compliant<sup><font size=-2>TM</font></sup> driver will always return true.
427 @return <code>true</code> if so; <code>false</code> otherwise
429 function TZPostgreSQLDatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean;
435 Does the database treat mixed case quoted SQL identifiers as
436 case insensitive and store them in upper case?
437 @return <code>true</code> if so; <code>false</code> otherwise
439 function TZPostgreSQLDatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean;
445 Does the database treat mixed case quoted SQL identifiers as
446 case insensitive and store them in lower case?
447 @return <code>true</code> if so; <code>false</code> otherwise
449 function TZPostgreSQLDatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean;
455 Does the database treat mixed case quoted SQL identifiers as
456 case insensitive and store them in mixed case?
457 @return <code>true</code> if so; <code>false</code> otherwise
459 function TZPostgreSQLDatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean;
465 Gets a comma-separated list of all a database's SQL keywords
466 that are NOT also SQL92 keywords.
469 function TZPostgreSQLDatabaseInfo.GetSQLKeywords: string;
471 Result := 'abort,absolute,access,action,add,admin,after,aggregate,all,also,'+
472 'alter,always,analyse,analyze,and,any,array,asc,assertion,assignment,'+
473 'asymmetric,at,authorization,'+
474 'backward,before,begin,between,bigint,binary,bit,boolean,both,'+
475 'cache,called,cascade,cascaded,case,cast,catalog,chain,character,'+
476 'characteristics,check,checkpoint,class,close,cluster,coalesce,'+
477 'collate,column,comment,commit,committed,concurrently,configuration,'+
478 'connect,connection,constraint,constraints,content,continue,'+
479 'conversion,convert,copy,cost,createdb,createrole,createuser,cross,'+
480 'csv,current,current_catalog,current_date,current_role,current_schema,'+
481 'current_time,current_timestamp,current_user,cursor,cycle,'+
482 'data,database,day,deallocate,dec,decimal,declare,default,defaults,'+
483 'deferrable,deferred,definer,delimiter,delimiters,desc,dictionary,'+
484 'disable,discard,distinct,do,document,domain,double,'+
485 'each,else,enable,encoding,encrypted,end,end-exec,enum,escape,except,'+
486 'excluding,exclusive,exec,execute,exists,explain,external,extract,'+
487 'false,family,fetch,first,float,following,for,force,foreign,forward,'+
488 'freeze,full,function,'+
489 'global,grant,granted,greatest,'+
490 'handler,header,hold,hour,'+
491 'identity,if,ilike,immediate,immutable,implicit,in,including,'+
492 'increment,indexes,inherit,inherits,initially,inner,inout,input,'+
493 'insensitive,instead,int,intersect,interval,invoker,isnull,isolation,'+
495 'lancompiler,language,large,last,lc_collate,lc_ctype,leading,least,'+
496 'left,level,like,limit,listen,load,local,localtime,localtimestamp,'+
497 'location,lock,login,'+
498 'mapping,match,maxvalue,minute,minvalue,mode,month,move,'+
499 'name,names,national,natural,nchar,new,next,no,nocreatedb,nocreaterole,'+
500 'nocreateuser,noinherit,nologin,none,nosuperuser,not,nothing,notify,'+
501 'notnull,nowait,nullif,nulls,numeric,'+
502 'object,of,off,offset,oids,old,only,operator,option,options,or,out,'+
503 'outer,over,overlaps,overlay,owned,owner,'+
504 'parser,partial,partition,password,placing,plans,position,preceding,'+
505 'precision,prepare,prepared,preserve,prior,privileges,procedural,'+
508 'range,read,real,reassign,recheck,recursive,references,reindex,'+
509 'relative,release,rename,repeatable,replace,replica,reset,restart,'+
510 'restrict,return,returning,returns,revoke,right,role,rollback,row,'+
512 'savepoint,schema,scroll,search,second,security,sequence,serializable,'+
513 'server,session,session_user,setof,share,show,similar,simple,smallint,'+
514 'some,stable,standalone,start,statement,statistics,stdin,stdout,'+
515 'storage,strict,strip,substring,superuser,symmetric,sysid,system,'+
516 'tablespace,temp,template,temporary,text,then,time,timestamp,to,'+
517 'trailing,transaction,treat,trigger,trim,true,truncate,trusted,type,'+
518 'unbounded,uncommitted,unencrypted,union,unique,unknown,unlisten,'+
520 'vacuum,valid,validator,value,variadic,varying,verbose,version,view,'+
522 'when,whitespace,window,with,without,work,wrapper,write,'+
523 'xml,xmlattributes,xmlconcat,xmlelement,xmlforest,xmlparse,xmlpi,'+
524 'xmlroot,xmlserialize,'+
530 Gets a comma-separated list of math functions. These are the
531 X/Open CLI math function names used in the JDBC function escape
535 function TZPostgreSQLDatabaseInfo.GetNumericFunctions: string;
541 Gets a comma-separated list of string functions. These are the
542 X/Open CLI string function names used in the JDBC function escape
546 function TZPostgreSQLDatabaseInfo.GetStringFunctions: string;
552 Gets a comma-separated list of system functions. These are the
553 X/Open CLI system function names used in the JDBC function escape
557 function TZPostgreSQLDatabaseInfo.GetSystemFunctions: string;
563 Gets a comma-separated list of time and date functions.
566 function TZPostgreSQLDatabaseInfo.GetTimeDateFunctions: string;
572 Gets the string that can be used to escape wildcard characters.
573 This is the string that can be used to escape '_' or '%' in
574 the string pattern style catalog search parameters.
576 <P>The '_' character represents any single character.
577 <P>The '%' character represents any sequence of zero or
580 @return the string used to escape wildcard characters
582 function TZPostgreSQLDatabaseInfo.GetSearchStringEscape: string;
588 Gets all the "extra" characters that can be used in unquoted
589 identifier names (those beyond a-z, A-Z, 0-9 and _).
590 @return the string containing the extra characters
592 function TZPostgreSQLDatabaseInfo.GetExtraNameCharacters: string;
597 //--------------------------------------------------------------------
598 // Functions describing which features are supported.
601 Are expressions in "ORDER BY" lists supported?
602 @return <code>true</code> if so; <code>false</code> otherwise
604 function TZPostgreSQLDatabaseInfo.SupportsExpressionsInOrderBy: Boolean;
610 Can an "ORDER BY" clause use columns not in the SELECT statement?
611 @return <code>true</code> if so; <code>false</code> otherwise
613 function TZPostgreSQLDatabaseInfo.SupportsOrderByUnrelated: Boolean;
615 Result := HasMinimumServerVersion(6, 4);
619 Is some form of "GROUP BY" clause supported?
620 @return <code>true</code> if so; <code>false</code> otherwise
622 function TZPostgreSQLDatabaseInfo.SupportsGroupBy: Boolean;
628 Can a "GROUP BY" clause use columns not in the SELECT?
629 @return <code>true</code> if so; <code>false</code> otherwise
631 function TZPostgreSQLDatabaseInfo.SupportsGroupByUnrelated: Boolean;
633 Result := HasMinimumServerVersion(6, 4);
637 Can a "GROUP BY" clause add columns not in the SELECT
638 provided it specifies all the columns in the SELECT?
639 @return <code>true</code> if so; <code>false</code> otherwise
641 function TZPostgreSQLDatabaseInfo.SupportsGroupByBeyondSelect: Boolean;
643 Result := HasMinimumServerVersion(6, 4);
647 Is the SQL Integrity Enhancement Facility supported?
648 @return <code>true</code> if so; <code>false</code> otherwise
650 function TZPostgreSQLDatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean;
656 What's the database vendor's preferred term for "schema"?
657 @return the vendor term
659 function TZPostgreSQLDatabaseInfo.GetSchemaTerm: string;
665 What's the database vendor's preferred term for "procedure"?
666 @return the vendor term
668 function TZPostgreSQLDatabaseInfo.GetProcedureTerm: string;
670 Result := 'function';
674 What's the database vendor's preferred term for "catalog"?
675 @return the vendor term
677 function TZPostgreSQLDatabaseInfo.GetCatalogTerm: string;
679 Result := 'database';
683 What's the separator between catalog and table name?
684 @return the separator string
686 function TZPostgreSQLDatabaseInfo.GetCatalogSeparator: string;
692 Can a schema name be used in a data manipulation statement?
693 @return <code>true</code> if so; <code>false</code> otherwise
695 function TZPostgreSQLDatabaseInfo.SupportsSchemasInDataManipulation: Boolean;
697 Result := HasMinimumServerVersion(7, 3);
701 Can a schema name be used in a procedure call statement?
702 @return <code>true</code> if so; <code>false</code> otherwise
704 function TZPostgreSQLDatabaseInfo.SupportsSchemasInProcedureCalls: Boolean;
706 Result := HasMinimumServerVersion(7, 3);
710 Can a schema name be used in a table definition statement?
711 @return <code>true</code> if so; <code>false</code> otherwise
713 function TZPostgreSQLDatabaseInfo.SupportsSchemasInTableDefinitions: Boolean;
715 Result := HasMinimumServerVersion(7, 3);
719 Can a schema name be used in an index definition statement?
720 @return <code>true</code> if so; <code>false</code> otherwise
722 function TZPostgreSQLDatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean;
724 Result := HasMinimumServerVersion(7, 3);
728 Can a schema name be used in a privilege definition statement?
729 @return <code>true</code> if so; <code>false</code> otherwise
731 function TZPostgreSQLDatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean;
733 Result := HasMinimumServerVersion(7, 3);
737 Can a catalog name be used in a data manipulation statement?
738 @return <code>true</code> if so; <code>false</code> otherwise
740 function TZPostgreSQLDatabaseInfo.SupportsCatalogsInDataManipulation: Boolean;
746 Can a catalog name be used in a procedure call statement?
747 @return <code>true</code> if so; <code>false</code> otherwise
749 function TZPostgreSQLDatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean;
751 Result := HasMinimumServerVersion(7, 3);
755 Can a catalog name be used in a table definition statement?
756 @return <code>true</code> if so; <code>false</code> otherwise
758 function TZPostgreSQLDatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean;
760 Result := HasMinimumServerVersion(7, 3);
764 Can a catalog name be used in an index definition statement?
765 @return <code>true</code> if so; <code>false</code> otherwise
767 function TZPostgreSQLDatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean;
773 Can a catalog name be used in a privilege definition statement?
774 @return <code>true</code> if so; <code>false</code> otherwise
776 function TZPostgreSQLDatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean;
782 Is positioned DELETE supported?
783 @return <code>true</code> if so; <code>false</code> otherwise
785 function TZPostgreSQLDatabaseInfo.SupportsPositionedDelete: Boolean;
791 Is positioned UPDATE supported?
792 @return <code>true</code> if so; <code>false</code> otherwise
794 function TZPostgreSQLDatabaseInfo.SupportsPositionedUpdate: Boolean;
800 Is SELECT for UPDATE supported?
801 @return <code>true</code> if so; <code>false</code> otherwise
803 function TZPostgreSQLDatabaseInfo.SupportsSelectForUpdate: Boolean;
805 Result := HasMinimumServerVersion(6, 5);
809 Are stored procedure calls using the stored procedure escape
811 @return <code>true</code> if so; <code>false</code> otherwise
813 function TZPostgreSQLDatabaseInfo.SupportsStoredProcedures: Boolean;
819 Are subqueries in comparison expressions supported?
820 A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
821 @return <code>true</code> if so; <code>false</code> otherwise
823 function TZPostgreSQLDatabaseInfo.SupportsSubqueriesInComparisons: Boolean;
829 Are subqueries in 'exists' expressions supported?
830 A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
831 @return <code>true</code> if so; <code>false</code> otherwise
833 function TZPostgreSQLDatabaseInfo.SupportsSubqueriesInExists: Boolean;
839 Are subqueries in 'in' statements supported?
840 A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
841 @return <code>true</code> if so; <code>false</code> otherwise
843 function TZPostgreSQLDatabaseInfo.SupportsSubqueriesInIns: Boolean;
849 Are subqueries in quantified expressions supported?
850 A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
851 @return <code>true</code> if so; <code>false</code> otherwise
853 function TZPostgreSQLDatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean;
859 Are correlated subqueries supported?
860 A JDBC Compliant<sup><font size=-2>TM</font></sup> driver always returns true.
861 @return <code>true</code> if so; <code>false</code> otherwise
863 function TZPostgreSQLDatabaseInfo.SupportsCorrelatedSubqueries: Boolean;
865 Result := HasMinimumServerVersion(7, 1);
869 Is SQL UNION supported?
870 @return <code>true</code> if so; <code>false</code> otherwise
872 function TZPostgreSQLDatabaseInfo.SupportsUnion: Boolean;
878 Is SQL UNION ALL supported?
879 @return <code>true</code> if so; <code>false</code> otherwise
881 function TZPostgreSQLDatabaseInfo.SupportsUnionAll: Boolean;
883 Result := HasMinimumServerVersion(7, 1);
887 Can cursors remain open across commits?
888 @return <code>true</code> if cursors always remain open;
889 <code>false</code> if they might not remain open
891 function TZPostgreSQLDatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean;
897 Can cursors remain open across rollbacks?
898 @return <code>true</code> if cursors always remain open;
899 <code>false</code> if they might not remain open
901 function TZPostgreSQLDatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean;
907 Can statements remain open across commits?
908 @return <code>true</code> if statements always remain open;
909 <code>false</code> if they might not remain open
911 function TZPostgreSQLDatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean;
917 Can statements remain open across rollbacks?
918 @return <code>true</code> if statements always remain open;
919 <code>false</code> if they might not remain open
921 function TZPostgreSQLDatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean;
926 //----------------------------------------------------------------------
927 // The following group of methods exposes various limitations
928 // based on the target database with the current driver.
929 // Unless otherwise specified, a result of zero means there is no
930 // limit, or the limit is not known.
933 How many hex characters can you have in an inline binary literal?
934 @return max binary literal length in hex characters;
935 a result of zero means that there is no limit or the limit is not known
937 function TZPostgreSQLDatabaseInfo.GetMaxBinaryLiteralLength: Integer;
943 What's the max length for a character literal?
944 @return max literal length;
945 a result of zero means that there is no limit or the limit is not known
947 function TZPostgreSQLDatabaseInfo.GetMaxCharLiteralLength: Integer;
953 What's the limit on column name length?
954 @return max column name length;
955 a result of zero means that there is no limit or the limit is not known
957 function TZPostgreSQLDatabaseInfo.GetMaxColumnNameLength: Integer;
959 Result := GetMaxNameLength;
963 What's the maximum number of columns in a "GROUP BY" clause?
964 @return max number of columns;
965 a result of zero means that there is no limit or the limit is not known
967 function TZPostgreSQLDatabaseInfo.GetMaxColumnsInGroupBy: Integer;
973 What's the maximum number of columns allowed in an index?
974 @return max number of columns;
975 a result of zero means that there is no limit or the limit is not known
977 function TZPostgreSQLDatabaseInfo.GetMaxColumnsInIndex: Integer;
979 Result := GetMaxIndexKeys;
983 What's the maximum number of columns in an "ORDER BY" clause?
984 @return max number of columns;
985 a result of zero means that there is no limit or the limit is not known
987 function TZPostgreSQLDatabaseInfo.GetMaxColumnsInOrderBy: Integer;
993 What's the maximum number of columns in a "SELECT" list?
994 @return max number of columns;
995 a result of zero means that there is no limit or the limit is not known
997 function TZPostgreSQLDatabaseInfo.GetMaxColumnsInSelect: Integer;
1003 What's the maximum number of columns in a table?
1004 @return max number of columns;
1005 a result of zero means that there is no limit or the limit is not known
1007 function TZPostgreSQLDatabaseInfo.GetMaxColumnsInTable: Integer;
1013 How many active connections can we have at a time to this database?
1014 @return max number of active connections;
1015 a result of zero means that there is no limit or the limit is not known
1017 function TZPostgreSQLDatabaseInfo.GetMaxConnections: Integer;
1023 What's the maximum cursor name length?
1024 @return max cursor name length in bytes;
1025 a result of zero means that there is no limit or the limit is not known
1027 function TZPostgreSQLDatabaseInfo.GetMaxCursorNameLength: Integer;
1029 Result := GetMaxNameLength;
1033 Retrieves the maximum number of bytes for an index, including all
1034 of the parts of the index.
1035 @return max index length in bytes, which includes the composite of all
1036 the constituent parts of the index;
1037 a result of zero means that there is no limit or the limit is not known
1039 function TZPostgreSQLDatabaseInfo.GetMaxIndexLength: Integer;
1045 What's the maximum length allowed for a schema name?
1046 @return max name length in bytes;
1047 a result of zero means that there is no limit or the limit is not known
1049 function TZPostgreSQLDatabaseInfo.GetMaxSchemaNameLength: Integer;
1051 Result := GetMaxNameLength;
1055 What's the maximum length of a procedure name?
1056 @return max name length in bytes;
1057 a result of zero means that there is no limit or the limit is not known
1059 function TZPostgreSQLDatabaseInfo.GetMaxProcedureNameLength: Integer;
1061 Result := GetMaxNameLength;
1065 What's the maximum length of a catalog name?
1066 @return max name length in bytes;
1067 a result of zero means that there is no limit or the limit is not known
1069 function TZPostgreSQLDatabaseInfo.GetMaxCatalogNameLength: Integer;
1071 Result := GetMaxNameLength;
1075 What's the maximum length of a single row?
1076 @return max row size in bytes;
1077 a result of zero means that there is no limit or the limit is not known
1079 function TZPostgreSQLDatabaseInfo.GetMaxRowSize: Integer;
1081 if HasMinimumServerVersion(7, 1) then
1082 Result := 1073741824
1083 else Result := 8192;
1087 Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY
1089 @return <code>true</code> if so; <code>false</code> otherwise
1091 function TZPostgreSQLDatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean;
1097 What's the maximum length of an SQL statement?
1098 @return max length in bytes;
1099 a result of zero means that there is no limit or the limit is not known
1101 function TZPostgreSQLDatabaseInfo.GetMaxStatementLength: Integer;
1103 if HasMinimumServerVersion(7, 0) then
1105 else Result := 16348
1109 How many active statements can we have open at one time to this
1111 @return the maximum number of statements that can be open at one time;
1112 a result of zero means that there is no limit or the limit is not known
1114 function TZPostgreSQLDatabaseInfo.GetMaxStatements: Integer;
1120 What's the maximum length of a table name?
1121 @return max name length in bytes;
1122 a result of zero means that there is no limit or the limit is not known
1124 function TZPostgreSQLDatabaseInfo.GetMaxTableNameLength: Integer;
1126 Result := GetMaxNameLength;
1130 What's the maximum number of tables in a SELECT statement?
1131 @return the maximum number of tables allowed in a SELECT statement;
1132 a result of zero means that there is no limit or the limit is not known
1134 function TZPostgreSQLDatabaseInfo.GetMaxTablesInSelect: Integer;
1140 What's the maximum length of a user name?
1141 @return max user name length in bytes;
1142 a result of zero means that there is no limit or the limit is not known
1144 function TZPostgreSQLDatabaseInfo.GetMaxUserNameLength: Integer;
1146 Result := GetMaxNameLength;
1149 //----------------------------------------------------------------------
1152 What's the database's default transaction isolation level? The
1153 values are defined in <code>java.sql.Connection</code>.
1154 @return the default isolation level
1157 function TZPostgreSQLDatabaseInfo.GetDefaultTransactionIsolation:
1158 TZTransactIsolationLevel;
1160 Result := tiReadCommitted;
1164 Are transactions supported? If not, invoking the method
1165 <code>commit</code> is a noop and the isolation level is TRANSACTION_NONE.
1166 @return <code>true</code> if transactions are supported; <code>false</code> otherwise
1168 function TZPostgreSQLDatabaseInfo.SupportsTransactions: Boolean;
1174 Does this database support the given transaction isolation level?
1175 @param level the values are defined in <code>java.sql.Connection</code>
1176 @return <code>true</code> if so; <code>false</code> otherwise
1179 function TZPostgreSQLDatabaseInfo.SupportsTransactionIsolationLevel(
1180 Level: TZTransactIsolationLevel): Boolean;
1182 Result := (Level = tiSerializable) or (Level = tiReadCommitted);
1186 Are both data definition and data manipulation statements
1187 within a transaction supported?
1188 @return <code>true</code> if so; <code>false</code> otherwise
1190 function TZPostgreSQLDatabaseInfo.
1191 SupportsDataDefinitionAndDataManipulationTransactions: Boolean;
1197 Are only data manipulation statements within a transaction
1199 @return <code>true</code> if so; <code>false</code> otherwise
1201 function TZPostgreSQLDatabaseInfo.
1202 SupportsDataManipulationTransactionsOnly: Boolean;
1208 Does a data definition statement within a transaction force the
1209 transaction to commit?
1210 @return <code>true</code> if so; <code>false</code> otherwise
1212 function TZPostgreSQLDatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean;
1218 Is a data definition statement within a transaction ignored?
1219 @return <code>true</code> if so; <code>false</code> otherwise
1221 function TZPostgreSQLDatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean;
1227 Does the database support the given result set type?
1228 @param type defined in <code>java.sql.ResultSet</code>
1229 @return <code>true</code> if so; <code>false</code> otherwise
1231 function TZPostgreSQLDatabaseInfo.SupportsResultSetType(
1232 _Type: TZResultSetType): Boolean;
1234 Result := _Type = rtScrollInsensitive;
1238 Does the database support the concurrency type in combination
1239 with the given result set type?
1241 @param type defined in <code>java.sql.ResultSet</code>
1242 @param concurrency type defined in <code>java.sql.ResultSet</code>
1243 @return <code>true</code> if so; <code>false</code> otherwise
1245 function TZPostgreSQLDatabaseInfo.SupportsResultSetConcurrency(
1246 _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean;
1248 Result := (_Type = rtScrollInsensitive) and (Concurrency = rcReadOnly);
1251 //----------------------------------------------------------------------
1252 // Additional functions.
1254 function TZPostgreSQLDatabaseInfo.HasMinimumServerVersion(
1255 MajorVersion: Integer; MinorVersion: Integer): Boolean;
1257 PostgreSQLConnection: IZPostgreSQLConnection;
1259 PostgreSQLConnection := Metadata.GetConnection as IZPostgreSQLConnection;
1260 Result := (MajorVersion < PostgreSQLConnection.GetServerMajorVersion)
1261 or ((MajorVersion = PostgreSQLConnection.GetServerMajorVersion)
1262 and (MinorVersion <= PostgreSQLConnection.GetServerMinorVersion));
1265 function TZPostgreSQLDatabaseInfo.GetMaxIndexKeys: Integer;
1269 if HasMinimumServerVersion(7, 3) then
1271 From := ' pg_catalog.pg_namespace n, pg_catalog.pg_type t1,'
1272 + ' pg_catalog.pg_type t2 WHERE t1.typnamespace=n.oid'
1273 + ' AND n.nspname=''pg_catalog'' AND ';
1275 From := ' pg_type t1, pg_type t2 WHERE ';
1276 SQL := ' SELECT t1.typlen/t2.typlen FROM ' + From
1277 + ' t1.typelem=t2.oid AND t1.typname=''oidvector'' ';
1279 with Metadata.GetConnection.CreateStatement.ExecuteQuery(SQL) do
1282 raise Exception.Create(SUnknownError); //CHANGE IT!
1283 Result := GetInt(1);
1288 function TZPostgreSQLDatabaseInfo.GetMaxNameLength: Integer;
1292 if HasMinimumServerVersion(7, 3) then
1294 SQL := ' SELECT t.typlen FROM pg_catalog.pg_type t,'
1295 + ' pg_catalog.pg_namespace n WHERE t.typnamespace=n.oid'
1296 + ' AND t.typname=''name'' AND n.nspname=''pg_catalog'' ';
1298 SQL := ' SELECT typlen FROM pg_type WHERE typname=''name'' ';
1300 with Metadata.GetConnection.CreateStatement.ExecuteQuery(SQL) do
1303 raise Exception.Create(SUnknownError); //CHANGE IT!
1304 Result := GetIntByName('typlen');
1310 { TZPostgreSQLDatabaseMetadata }
1314 Destroys this object and cleanups the memory.
1316 destructor TZPostgreSQLDatabaseMetadata.Destroy;
1322 Constructs a database information object and returns the interface to it. Used
1323 internally by the constructor.
1324 @return the database information object interface
1326 function TZPostgreSQLDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo;
1328 Result := TZPostgreSQLDatabaseInfo.Create(Self);
1333 @return escaped string
1335 function TZPostgreSQLDatabaseMetadata.EscapeString(const S: string): string;
1340 for I := Length(Result) downto 1 do
1341 if (Result[I] = '''') or (Result[I] = '\') then
1342 Insert('\', Result, I);
1343 Result := '''' + Result + '''';
1344 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(8, 1) then
1345 Result := 'E' + Result;
1348 function TZPostgreSQLDatabaseMetadata.GetRuleType(const Rule: String): TZImportedKey;
1350 if Rule = 'RESTRICT' then
1351 Result := ikRestrict
1352 else if Rule = 'NO ACTION' then
1353 Result := ikNoAction
1354 else if Rule = 'CASCADE' then
1356 else if Rule = 'SET DEFAULT' then
1357 Result := ikSetDefault
1358 else if Rule = 'SET NULL' then
1361 Result := ikNotDeferrable; //impossible!
1365 Gets a description of the stored procedures available in a
1368 <P>Only procedure descriptions matching the schema and
1369 procedure name criteria are returned. They are ordered by
1370 PROCEDURE_SCHEM, and PROCEDURE_NAME.
1372 <P>Each procedure description has the the following columns:
1374 <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
1375 <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
1376 <LI><B>PROCEDURE_NAME</B> String => procedure name
1377 <LI> reserved for future use
1378 <LI> reserved for future use
1379 <LI> reserved for future use
1380 <LI><B>REMARKS</B> String => explanatory comment on the procedure
1381 <LI><B>PROCEDURE_TYPE</B> short => kind of procedure:
1383 <LI> procedureResultUnknown - May return a result
1384 <LI> procedureNoResult - Does not return a result
1385 <LI> procedureReturnsResult - Returns a result
1389 @param catalog a catalog name; "" retrieves those without a
1390 catalog; null means drop catalog name from the selection criteria
1391 @param schemaPattern a schema name pattern; "" retrieves those
1393 @param procedureNamePattern a procedure name pattern
1394 @return <code>ResultSet</code> - each row is a procedure description
1395 @see #getSearchStringEscape
1397 function TZPostgreSQLDatabaseMetadata.UncachedGetProcedures(const Catalog: string;
1398 const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet;
1400 SQL, ProcedureCondition, SchemaCondition: string;
1402 SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname');
1403 ProcedureCondition := ConstructNameCondition(ProcedureNamePattern,'p.proname');
1404 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
1406 SQL := 'SELECT NULL AS PROCEDURE_CAT, n.nspname AS PROCEDURE_SCHEM,'
1407 + ' p.proname AS PROCEDURE_NAME, NULL AS RESERVED1, NULL AS RESERVED2,'
1408 + ' NULL AS RESERVED3, d.description AS REMARKS, '
1409 + IntToStr(ProcedureReturnsResult) + ' AS PROCEDURE_TYPE '
1410 + ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_proc p '
1411 + ' LEFT JOIN pg_catalog.pg_description d ON (p.oid=d.objoid) '
1412 + ' LEFT JOIN pg_catalog.pg_class c ON (d.classoid=c.oid AND'
1413 + ' c.relname=''pg_proc'') LEFT JOIN pg_catalog.pg_namespace pn ON'
1414 + ' (c.relnamespace=pn.oid AND pn.nspname=''pg_catalog'') '
1415 + ' WHERE p.pronamespace=n.oid';
1416 if SchemaCondition <> '' then
1417 SQL := SQL + ' AND ' + Schemacondition;
1418 if ProcedureCondition <> '' then
1419 SQL := SQL + ' AND ' + ProcedureCondition;
1420 SQL := SQL + ' ORDER BY PROCEDURE_SCHEM, PROCEDURE_NAME';
1424 SQL := 'SELECT NULL AS PROCEDURE_CAT, NULL AS PROCEDURE_SCHEM,'
1425 + ' p.proname AS PROCEDURE_NAME, NULL AS RESERVED1, NULL AS RESERVED2,'
1426 + ' NULL AS RESERVED3, NULL AS REMARKS, '
1427 + IntToStr(ProcedureReturnsResult) + ' AS PROCEDURE_TYPE'
1428 + ' FROM pg_proc p';
1429 if ProcedureCondition <> '' then
1430 SQL := SQL + ' WHERE ' + ProcedureCondition;
1431 SQL := SQL + ' ORDER BY PROCEDURE_NAME';
1434 Result := CopyToVirtualResultSet(
1435 GetConnection.CreateStatement.ExecuteQuery(SQL),
1436 ConstructVirtualResultSet(ProceduresColumnsDynArray));
1440 Gets a description of a catalog's stored procedure parameters
1443 <P>Only descriptions matching the schema, procedure and
1444 parameter name criteria are returned. They are ordered by
1445 PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value,
1446 if any, is first. Next are the parameter descriptions in call
1447 order. The column descriptions follow in column number order.
1449 <P>Each row in the <code>ResultSet</code> is a parameter description or
1450 column description with the following fields:
1452 <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
1453 <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
1454 <LI><B>PROCEDURE_NAME</B> String => procedure name
1455 <LI><B>COLUMN_NAME</B> String => column/parameter name
1456 <LI><B>COLUMN_TYPE</B> Short => kind of column/parameter:
1458 <LI> procedureColumnUnknown - nobody knows
1459 <LI> procedureColumnIn - IN parameter
1460 <LI> procedureColumnInOut - INOUT parameter
1461 <LI> procedureColumnOut - OUT parameter
1462 <LI> procedureColumnReturn - procedure return value
1463 <LI> procedureColumnResult - result column in <code>ResultSet</code>
1465 <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
1466 <LI><B>TYPE_NAME</B> String => SQL type name, for a UDT type the
1467 type name is fully qualified
1468 <LI><B>PRECISION</B> int => precision
1469 <LI><B>LENGTH</B> int => length in bytes of data
1470 <LI><B>SCALE</B> short => scale
1471 <LI><B>RADIX</B> short => radix
1472 <LI><B>NULLABLE</B> short => can it contain NULL?
1474 <LI> procedureNoNulls - does not allow NULL values
1475 <LI> procedureNullable - allows NULL values
1476 <LI> procedureNullableUnknown - nullability unknown
1478 <LI><B>REMARKS</B> String => comment describing parameter/column
1481 <P><B>Note:</B> Some databases may not return the column
1482 descriptions for a procedure. Additional columns beyond
1483 REMARKS can be defined by the database.
1485 @param catalog a catalog name; "" retrieves those without a
1486 catalog; null means drop catalog name from the selection criteria
1487 @param schemaPattern a schema name pattern; "" retrieves those
1489 @param procedureNamePattern a procedure name pattern
1490 @param columnNamePattern a column name pattern
1491 @return <code>ResultSet</code> - each row describes a stored procedure parameter or
1493 @see #getSearchStringEscape
1495 function TZPostgreSQLDatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string;
1496 const SchemaPattern: string; const ProcedureNamePattern: string;
1497 const ColumnNamePattern: string): IZResultSet;
1499 procedure InsertProcedureColumnRow(AResultSet: IZResultSet;
1500 const ASchema, AProcedureName, AColumnName: string;
1501 const AColumnType, ADataType: integer; const ATypeName: string;
1502 const ANullable: integer);
1504 AResultSet.MoveToInsertRow;
1505 AResultSet.UpdateNullByName('PROCEDURE_CAT');
1506 AResultSet.UpdateStringByName('PROCEDURE_SCHEM', ASchema);
1507 AResultSet.UpdateStringByName('PROCEDURE_NAME', AProcedureName);
1508 AResultSet.UpdateStringByName('COLUMN_NAME', AColumnName);
1509 AResultSet.UpdateIntByName('COLUMN_TYPE', AColumnType);
1510 AResultSet.UpdateIntByName('DATA_TYPE', ADataType);
1511 AResultSet.UpdateStringByName('TYPE_NAME', ATypeName);
1512 AResultSet.UpdateNullByName('PRECISION');
1513 AResultSet.UpdateNullByName('LENGTH');
1514 AResultSet.UpdateNullByName('SCALE');
1515 AResultSet.UpdateNullByName('RADIX');
1516 AResultSet.UpdateIntByName('NULLABLE', ANullable);
1517 AResultSet.UpdateNullByName('REMARKS');
1518 AResultSet.InsertRow;
1522 I, ReturnType, ColumnTypeOid, ArgOid: Integer;
1523 SQL, ReturnTypeType: string;
1524 IsInParam, IsOutParam: Boolean;
1525 ArgTypes, ArgNames, ArgModes: TStrings;
1526 Ver73Up, Ver80Up: Boolean;
1527 ResultSet: IZResultSet;
1528 ColumnsRS: IZResultSet;
1530 OutParamCount: Integer;
1532 ColumnType: Integer;
1533 ProcedureCondition, SchemaCondition: string;
1535 SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname');
1536 ProcedureCondition := ConstructNameCondition(ProcedureNamePattern,'p.proname');
1537 Result := inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern);
1539 Ver80Up := (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(8, 0);
1540 Ver73Up := Ver80Up or (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3);
1543 SQL := 'SELECT n.nspname,p.proname,p.prorettype,p.proargtypes,t.typtype,'
1544 + 'p.proallargtypes,p.proargnames,p.proargmodes,t.typrelid '
1545 + 'FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n, pg_catalog.pg_type t '
1546 + 'WHERE p.pronamespace=n.oid AND p.prorettype=t.oid';
1547 if SchemaPattern <> '' then
1548 SQL := SQL + ' AND ' + SchemaCondition;
1549 if ProcedureNamePattern <> '' then
1550 SQL := SQL + ' AND ' + ProcedureCondition;
1551 SQL := SQL + ' ORDER BY n.nspname, p.proname';
1556 SQL := 'SELECT n.nspname,p.proname,p.prorettype,p.proargtypes,t.typtype,'
1557 + 'NULL AS proallargtypes,NULL AS proargnames,NULL AS proargnames,t.typrelid '
1558 + 'FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n,'
1559 + ' pg_catalog.pg_type t WHERE p.pronamespace=n.oid AND p.prorettype=t.oid';
1560 if SchemaPattern <> '' then
1561 SQL := SQL + ' AND ' + SchemaCondition;
1562 if ProcedureNamePattern <> '' then
1563 SQL := SQL + ' AND ' + ProcedureCondition;
1564 SQL := SQL + ' ORDER BY n.nspname, p.proname';
1568 SQL := 'SELECT NULL AS nspname,p.proname,p.prorettype,p.proargtypes,'
1569 + ' NULL AS proallargtypes,NULL AS proargnames,NULL AS proargnames,t.typtype,t.typrelid'
1570 + ' FROM pg_proc p, pg_type t'
1571 + ' WHERE p.prorettype=t.oid';
1572 if ProcedureNamePattern <> '' then
1573 SQL := SQL + ' AND ' + ProcedureCondition;
1574 SQL := SQL + ' ORDER BY p.proname';
1577 ArgTypes := TStringList.Create;
1578 ArgNames := TStringList.Create;
1579 ArgModes := TStringList.Create;
1581 ResultSet := GetConnection.CreateStatement.ExecuteQuery(SQL); //FirmOS Patch
1586 ReturnType := StrToInt(GetStringByName('prorettype'));
1587 ReturnTypeType := GetStringByName('typtype');
1593 if (IsNullByName('proallargtypes')) then
1594 PutSplitString(ArgTypes, GetStringByName('proargtypes'), #10#13#9' ')
1596 ParseACLArray(ArgTypes, GetStringByName('proallargtypes'));
1597 ParseACLArray(ArgNames, GetStringByName('proargnames'));
1598 ParseACLArray(ArgModes, GetStringByName('proargmodes'));
1601 for I := 0 to ArgTypes.Count - 1 do
1604 IsOutParam := False;
1605 if ArgModes.Count > I then
1607 ArgMode := ArgModes[I][1];
1608 IsInParam := CharInSet(ArgMode, ['i', 'b', 'v']);
1609 IsOutParam := CharInSet(ArgMode, ['o', 'b', 't']);
1616 ArgOid := StrToInt(ArgTypes.Strings[i]);
1617 if ArgNames.Count > I then
1618 ColumnName := ArgNames.Strings[I]
1620 ColumnName := '$' + IntToStr(I + 1);
1626 ColumnType := Ord(pctInOut)
1628 ColumnType := Ord(pctIn);
1633 ColumnType := Ord(pctOut)
1635 ColumnType := Ord(pctUnknown);
1638 InsertProcedureColumnRow(Result, GetStringByName('nspname'),
1639 GetStringByName('proname'), ColumnName, ColumnType,
1640 Ord(GetSQLTypeByOid(ArgOid)), GetPostgreSQLType(ArgOid),
1641 Ord(ntNullableUnknown));
1644 if (OutParamCount > 0) then
1647 if (ReturnTypeType = 'c') then // Extract composit type columns
1649 ColumnsRS := GetConnection.CreateStatement.ExecuteQuery(
1650 Format('SELECT a.attname,a.atttypid'
1651 + ' FROM pg_catalog.pg_attribute a WHERE a.attrelid=%s'
1652 + ' ORDER BY a.attnum',
1653 [ResultSet.GetStringByName('typrelid')]));
1654 while ColumnsRS.Next do
1656 ColumnTypeOid := ColumnsRS.GetIntByName('atttypid');
1657 InsertProcedureColumnRow(Result, GetStringByName('nspname'),
1658 GetStringByName('proname'), ColumnsRS.GetStringByName('attname'),
1659 Ord(pctResultSet), Ord(GetSQLTypeByOid(ColumnTypeOid)),
1660 GetPostgreSQLType(ColumnTypeOid), Ord(ntNullableUnknown));
1666 if (ReturnTypeType <> 'p') then // Single non-pseudotype return value
1668 InsertProcedureColumnRow(Result, GetStringByName('nspname'),
1669 GetStringByName('proname'), 'returnValue', Ord(pctReturn),
1670 Ord(GetSQLTypeByOid(ReturnType)), GetPostgreSQLType(ReturnType),
1671 Ord(ntNullableUnknown));
1685 Gets a description of tables available in a catalog.
1687 <P>Only table descriptions matching the catalog, schema, table
1688 name and type criteria are returned. They are ordered by
1689 TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.
1691 <P>Each table description has the following columns:
1693 <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1694 <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1695 <LI><B>TABLE_NAME</B> String => table name
1696 <LI><B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
1697 "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
1698 "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
1699 <LI><B>REMARKS</B> String => explanatory comment on the table
1702 <P><B>Note:</B> Some databases may not return information for
1705 @param catalog a catalog name; "" retrieves those without a
1706 catalog; null means drop catalog name from the selection criteria
1707 @param schemaPattern a schema name pattern; "" retrieves those
1709 @param tableNamePattern a table name pattern
1710 @param types a list of table types to include; null returns all types
1711 @return <code>ResultSet</code> - each row is a table description
1712 @see #getSearchStringEscape
1714 function TZPostgreSQLDatabaseMetadata.UncachedGetTables(const Catalog: string;
1715 const SchemaPattern: string; const TableNamePattern: string;
1716 const Types: TStringDynArray): IZResultSet;
1719 TableType, OrderBy, SQL: string;
1720 UseSchemas: Boolean;
1721 LTypes: TStringDynArray;
1722 TableNameCondition, SchemaCondition: string;
1724 SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname');
1725 TableNameCondition := ConstructNameCondition(TableNamePattern,'c.relname');
1728 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
1730 SQL := ' SELECT NULL AS TABLE_CAT, n.nspname AS TABLE_SCHEM,'
1731 + ' c.relname AS TABLE_NAME, '
1732 + ' CASE (n.nspname LIKE ''pg\\_%'')'
1733 + ' OR (n.nspname=''information_schema'')'
1734 + ' WHEN true THEN CASE n.nspname '
1735 + ' WHEN ''pg_catalog'' THEN CASE c.relkind '
1736 + ' WHEN ''r'' THEN ''SYSTEM TABLE'''
1737 + ' WHEN ''v'' THEN ''SYSTEM VIEW'' '
1738 + ' WHEN ''i'' THEN ''SYSTEM INDEX'' '
1741 + ' WHEN ''information_schema'' THEN CASE c.relkind '
1742 + ' WHEN ''r'' THEN ''SYSTEM TABLE'''
1743 + ' WHEN ''v'' THEN ''SYSTEM VIEW'' '
1744 + ' WHEN ''i'' THEN ''SYSTEM INDEX'' '
1747 + ' WHEN ''pg_toast'' THEN CASE c.relkind '
1748 + ' WHEN ''r'' THEN ''SYSTEM TOAST TABLE'' '
1749 + ' WHEN ''i'' THEN ''SYSTEM TOAST INDEX'' '
1752 + ' ELSE CASE c.relkind '
1753 + ' WHEN ''r'' THEN ''TEMPORARY TABLE'' '
1754 + ' WHEN ''i'' THEN ''TEMPORARY INDEX'' '
1758 + ' WHEN false THEN CASE c.relkind '
1759 + ' WHEN ''r'' THEN ''TABLE'' '
1760 + ' WHEN ''i'' THEN ''INDEX'' '
1761 + ' WHEN ''S'' THEN ''SEQUENCE'' '
1762 + ' WHEN ''v'' THEN ''VIEW'' '
1767 + ' AS TABLE_TYPE, d.description AS REMARKS '
1768 + ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class c '
1769 + ' LEFT JOIN pg_catalog.pg_description d'
1770 + ' ON (c.oid = d.objoid AND d.objsubid = 0) '
1771 + ' LEFT JOIN pg_catalog.pg_class dc ON (d.classoid=dc.oid'
1772 + ' AND dc.relname=''pg_class'') LEFT JOIN pg_catalog.pg_namespace dn'
1773 + ' ON (dn.oid=dc.relnamespace AND dn.nspname=''pg_catalog'') '
1774 + ' WHERE c.relnamespace = n.oid ';
1775 if SchemaPattern <> '' then
1777 SQL := SQL + ' AND ' + SchemaCondition;
1779 OrderBy := ' ORDER BY TABLE_TYPE,TABLE_SCHEM,TABLE_NAME';
1783 UseSchemas := False;
1784 TableType := ' CASE c.relname LIKE ''pg\\_%'' '
1785 + 'WHEN true THEN CASE c.relname LIKE ''pg\\_toast\\_%'' '
1786 + 'WHEN true THEN CASE c.relkind '
1787 + ' WHEN ''r'' THEN ''SYSTEM TOAST TABLE'' '
1788 + ' WHEN ''i'' THEN ''SYSTEM TOAST INDEX'' '
1791 + 'WHEN false THEN CASE c.relname LIKE ''pg\\_temp\\_%'' '
1792 + ' WHEN true THEN CASE c.relkind '
1793 + ' WHEN ''r'' THEN ''TEMPORARY TABLE'' '
1794 + ' WHEN ''i'' THEN ''TEMPORARY INDEX'' '
1797 + ' WHEN false THEN CASE c.relkind '
1798 + ' WHEN ''r'' THEN ''SYSTEM TABLE'' '
1799 + ' WHEN ''v'' THEN ''SYSTEM VIEW'' '
1800 + ' WHEN ''i'' THEN ''SYSTEM INDEX'' '
1807 + 'WHEN false THEN CASE c.relkind '
1808 + ' WHEN ''r'' THEN ''TABLE'' '
1809 + ' WHEN ''i'' THEN ''INDEX'' '
1810 + ' WHEN ''S'' THEN ''SEQUENCE'' '
1811 + ' WHEN ''v'' THEN ''VIEW'' '
1816 OrderBy := ' ORDER BY TABLE_TYPE,TABLE_NAME ';
1817 SQL := 'SELECT NULL AS TABLE_CAT, NULL AS TABLE_SCHEM,'
1818 + ' c.relname AS TABLE_NAME, ' + TableType + ' AS TABLE_TYPE,'
1819 + ' NULL AS REMARKS FROM pg_class c WHERE true ';
1822 if (Types = nil) or (Length(Types) = 0) then
1824 SetLength(LTypes, 3);
1825 // SetLength(LTypes, 6);
1826 LTypes[0] := 'TABLE';
1827 LTypes[1] := 'VIEW';
1828 LTypes[2] := 'TEMPORARY TABLE';
1829 // LTypes[3] := 'SYSTEM TABLE';
1830 // LTypes[4] := 'SYSTEM TOAST TABLE';
1831 // LTypes[5] := 'SYSTEM VIEW';
1836 If TableNameCondition <> '' then
1837 SQL := SQL + ' AND ' + TableNameCondition;
1839 SQL := SQL + ' AND (false';
1840 for I := 0 to High(LTypes) do
1841 SQL := SQL + ' OR (' + TableTypeSQLExpression(LTypes[i], UseSchemas) + ')';
1842 SQL := SQL + ')' + OrderBy;
1844 Result := CopyToVirtualResultSet(
1845 GetConnection.CreateStatement.ExecuteQuery(SQL),
1846 ConstructVirtualResultSet(TableColumnsDynArray));
1850 Gets the schema names available in this database. The results
1851 are ordered by schema name.
1853 <P>The schema column is:
1855 <LI><B>TABLE_SCHEM</B> String => schema name
1858 @return <code>ResultSet</code> - each row has a single String column that is a
1861 function TZPostgreSQLDatabaseMetadata.UncachedGetSchemas: IZResultSet;
1865 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
1867 SQL := 'SELECT nspname AS TABLE_SCHEM FROM pg_catalog.pg_namespace'
1868 + ' WHERE nspname <> ''pg_toast'' AND nspname NOT'
1869 + ' LIKE ''pg\\_temp\\_%'' ORDER BY TABLE_SCHEM';
1871 SQL := 'SELECT ''''::text AS TABLE_SCHEM ORDER BY TABLE_SCHEM';
1873 Result := CopyToVirtualResultSet(
1874 GetConnection.CreateStatement.ExecuteQuery(SQL),
1875 ConstructVirtualResultSet(SchemaColumnsDynArray));
1879 Gets the catalog names available in this database. The results
1880 are ordered by catalog name.
1882 <P>The catalog column is:
1884 <LI><B>TABLE_CAT</B> String => catalog name
1887 @return <code>ResultSet</code> - each row has a single String column that is a
1890 function TZPostgreSQLDatabaseMetadata.UncachedGetCatalogs: IZResultSet;
1894 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
1896 SQL := 'SELECT datname AS TABLE_CAT FROM pg_catalog.pg_database'
1897 + ' ORDER BY TABLE_CAT';
1899 SQL := 'SELECT datname AS TABLE_CAT FROM pg_database ORDER BY TABLE_CAT';
1901 Result := CopyToVirtualResultSet(
1902 GetConnection.CreateStatement.ExecuteQuery(SQL),
1903 ConstructVirtualResultSet(CatalogColumnsDynArray));
1907 Gets the table types available in this database. The results
1908 are ordered by table type.
1910 <P>The table type is:
1912 <LI><B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
1913 "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
1914 "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
1917 @return <code>ResultSet</code> - each row has a single String column that is a
1920 function TZPostgreSQLDatabaseMetadata.UncachedGetTableTypes: IZResultSet;
1922 Types: array [0..10] of string = ('TABLE', 'VIEW', 'INDEX',
1923 'SEQUENCE', 'SYSTEM TABLE', 'SYSTEM TOAST TABLE',
1924 'SYSTEM TOAST INDEX', 'SYSTEM VIEW', 'SYSTEM INDEX',
1925 'TEMPORARY TABLE', 'TEMPORARY INDEX');
1929 Result:=inherited UncachedGetTableTypes;
1933 Result.MoveToInsertRow;
1934 Result.UpdateString(1, Types[I]);
1940 Gets a description of table columns available in
1941 the specified catalog.
1943 <P>Only column descriptions matching the catalog, schema, table
1944 and column name criteria are returned. They are ordered by
1945 TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.
1947 <P>Each column description has the following columns:
1949 <LI><B>TABLE_CAT</B> String => table catalog (may be null)
1950 <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
1951 <LI><B>TABLE_NAME</B> String => table name
1952 <LI><B>COLUMN_NAME</B> String => column name
1953 <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
1954 <LI><B>TYPE_NAME</B> String => Data source dependent type name,
1955 for a UDT the type name is fully qualified
1956 <LI><B>COLUMN_SIZE</B> int => column size. For char or date
1957 types this is the maximum number of characters, for numeric or
1958 decimal types this is precision.
1959 <LI><B>BUFFER_LENGTH</B> is not used.
1960 <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
1961 <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
1962 <LI><B>NULLABLE</B> int => is NULL allowed?
1964 <LI> columnNoNulls - might not allow NULL values
1965 <LI> columnNullable - definitely allows NULL values
1966 <LI> columnNullableUnknown - nullability unknown
1968 <LI><B>REMARKS</B> String => comment describing column (may be null)
1969 <LI><B>COLUMN_DEF</B> String => default value (may be null)
1970 <LI><B>SQL_DATA_TYPE</B> int => unused
1971 <LI><B>SQL_DATETIME_SUB</B> int => unused
1972 <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
1973 maximum number of bytes in the column
1974 <LI><B>ORDINAL_POSITION</B> int => index of column in table
1976 <LI><B>IS_NULLABLE</B> String => "NO" means column definitely
1977 does not allow NULL values; "YES" means the column might
1978 allow NULL values. An empty string means nobody knows.
1981 @param catalog a catalog name; "" retrieves those without a
1982 catalog; null means drop catalog name from the selection criteria
1983 @param schemaPattern a schema name pattern; "" retrieves those
1985 @param tableNamePattern a table name pattern
1986 @param columnNamePattern a column name pattern
1987 @return <code>ResultSet</code> - each row is a column description
1988 @see #getSearchStringEscape
1990 function TZPostgreSQLDatabaseMetadata.UncachedGetColumns(const Catalog: string;
1991 const SchemaPattern: string; const TableNamePattern: string;
1992 const ColumnNamePattern: string): IZResultSet;
1994 TypeOid, AttTypMod: Integer;
1995 SQL, PgType: string;
1997 CheckVisibility: Boolean;
1998 ColumnNameCondition, TableNameCondition, SchemaCondition: string;
2000 CheckVisibility := (GetConnection as IZPostgreSQLConnection).CheckFieldVisibility; //http://zeoslib.sourceforge.net/viewtopic.php?f=40&t=11174
2001 SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname');
2002 TableNameCondition := ConstructNameCondition(TableNamePattern,'c.relname');
2003 ColumnNameCondition := ConstructNameCondition(ColumnNamePattern,'a.attname');
2004 Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern);
2006 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
2008 SQL := 'SELECT n.nspname,' {nspname_index}
2009 + 'c.relname,' {relname_index}
2010 + 'a.attname,' {attname_index}
2011 + 'a.atttypid,' {atttypid_index}
2012 + 'a.attnotnull,' {attnotnull_index}
2013 + 'a.atttypmod,' {atttypmod_index}
2014 + 'a.attlen,' {attlen_index}
2015 + 'a.attnum,' {attnum_index}
2016 + 'pg_get_expr(def.adbin, def.adrelid) as adsrc,' {adsrc_index}
2017 + 'dsc.description ' {description_index}
2018 + ' FROM pg_catalog.pg_namespace n '
2019 + ' JOIN pg_catalog.pg_class c ON (c.relnamespace = n.oid) '
2020 + ' JOIN pg_catalog.pg_attribute a ON (a.attrelid=c.oid) '
2021 + ' LEFT JOIN pg_catalog.pg_attrdef def ON (a.attrelid=def.adrelid'
2022 + ' AND a.attnum = def.adnum) LEFT JOIN pg_catalog.pg_description dsc'
2023 + ' ON (c.oid=dsc.objoid AND a.attnum = dsc.objsubid) '
2024 + ' LEFT JOIN pg_catalog.pg_class dc ON (dc.oid=dsc.classoid'
2025 + ' AND dc.relname=''pg_class'') LEFT JOIN pg_catalog.pg_namespace dn'
2026 + ' ON (dc.relnamespace=dn.oid AND dn.nspname=''pg_catalog'') '
2027 + ' WHERE a.attnum > 0 AND NOT a.attisdropped';
2028 if SchemaPattern <> '' then
2029 SQL := SQL + ' AND ' + SchemaCondition
2031 //not by default: because of Speed decrease: http://http://zeoslib.sourceforge.net/viewtopic.php?p=16646&sid=130
2032 if CheckVisibility then
2033 SQL := SQL + ' AND pg_table_is_visible (c.oid) ';
2037 SQL := 'SELECT NULL::text AS nspname,' {1}
2041 + 'a.attnotnull,' {5}
2042 + 'a.atttypmod,' {6}
2045 + 'NULL AS adsrc,' {9}
2046 + 'NULL AS description' {10}
2047 + 'FROM pg_class c, pg_attribute a '
2048 + ' WHERE a.attrelid=c.oid AND a.attnum > 0 ';
2051 If TableNameCondition <> '' then
2052 SQL := SQL + ' AND ' + TableNameCondition;
2053 If ColumnNameCondition <> '' then
2054 SQL := SQL+ ' AND ' + ColumnNameCondition;
2055 SQL := SQL+ ' ORDER BY nspname,relname,attnum';
2057 with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2061 AttTypMod := GetInt(6 {atttypmod});
2063 TypeOid := GetInt(4 {atttypid});
2064 PgType := GetPostgreSQLType(TypeOid);
2066 Result.MoveToInsertRow;
2067 Result.UpdateNull(1);
2068 Result.UpdateString(2, GetString(1 {nspname}));
2069 Result.UpdateString(3, GetString(2 {relname}));
2070 Result.UpdateString(4, GetString(3 {attname}));
2071 SQLType := GetSQLTypeByOid(TypeOid);
2072 Result.UpdateInt(5, Ord(SQLType));
2073 Result.UpdateString(6, PgType);
2074 Result.UpdateInt(8, 0);
2076 if (PgType = 'bpchar') or (PgType = 'varchar') or (PgType = 'enum') then
2078 if AttTypMod <> -1 then
2079 Result.UpdateInt(7, GetFieldSize(SQLType, ConSettings, (AttTypMod - 4),
2080 ConSettings.ClientCodePage.CharWidth))
2082 if (PgType = 'varchar') then
2083 if ( (GetConnection as IZPostgreSQLConnection).GetUndefinedVarcharAsStringLength = 0 ) then
2085 Result.UpdateInt(5, Ord(GetSQLTypeByOid(25))); //Assume text-lob instead
2086 Result.UpdateInt(7, 0); // need no size for streams
2088 else //keep the string type but with user defined count of chars
2089 Result.UpdateInt(7, (GetConnection as IZPostgreSQLConnection).GetUndefinedVarcharAsStringLength )
2091 Result.UpdateInt(7, 0);
2093 else if (PgType = 'numeric') or (PgType = 'decimal') then
2095 Result.UpdateInt(7, ((AttTypMod - 4) div 65536)); //precision
2096 Result.UpdateInt(9, ((AttTypMod -4) mod 65536)); //scale
2097 Result.UpdateInt(10, 10); //base? ten as default
2099 else if (PgType = 'bit') or (PgType = 'varbit') then
2101 Result.UpdateInt(7, AttTypMod);
2102 Result.UpdateInt(10, 2);
2106 Result.UpdateInt(7, GetInt(7 {attlen}));
2107 Result.UpdateInt(10, 2);
2110 Result.UpdateNull(8);
2111 if GetBoolean(5 {attnotnull}) then
2113 Result.UpdateString(18, 'NO');
2114 Result.UpdateInt(11, Ord(ntNoNulls));
2118 Result.UpdateString(18, 'YES');
2119 Result.UpdateInt(11, Ord(ntNullable));
2122 Result.UpdateString(12, GetString(10 {description}));
2123 Result.UpdateString(13, GetString(9 {adsrc}));
2124 Result.UpdateNull(14);
2125 Result.UpdateNull(15);
2126 Result.UpdateInt(16, Result.GetInt(7));
2127 Result.UpdateInt(17, GetInt(8 {attnum}));
2129 Result.UpdateNullByName('AUTO_INCREMENT');
2130 Result.UpdateBooleanByName('CASE_SENSITIVE',
2131 IC.IsCaseSensitive(GetString(3 {attname})));
2132 Result.UpdateBooleanByName('SEARCHABLE', True);
2133 Result.UpdateBooleanByName('WRITABLE', True);
2134 Result.UpdateBooleanByName('DEFINITELYWRITABLE', True);
2135 Result.UpdateBooleanByName('READONLY', False);
2144 Gets a description of the access rights for a table's columns.
2146 <P>Only privileges matching the column name criteria are
2147 returned. They are ordered by COLUMN_NAME and PRIVILEGE.
2149 <P>Each privilige description has the following columns:
2151 <LI><B>TABLE_CAT</B> String => table catalog (may be null)
2152 <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
2153 <LI><B>TABLE_NAME</B> String => table name
2154 <LI><B>COLUMN_NAME</B> String => column name
2155 <LI><B>GRANTOR</B> => grantor of access (may be null)
2156 <LI><B>GRANTEE</B> String => grantee of access
2157 <LI><B>PRIVILEGE</B> String => name of access (SELECT,
2158 INSERT, UPDATE, REFRENCES, ...)
2159 <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
2160 to grant to others; "NO" if not; null if unknown
2163 @param catalog a catalog name; "" retrieves those without a
2164 catalog; null means drop catalog name from the selection criteria
2165 @param schema a schema name; "" retrieves those without a schema
2166 @param table a table name
2167 @param columnNamePattern a column name pattern
2168 @return <code>ResultSet</code> - each row is a column privilege description
2169 @see #getSearchStringEscape
2171 function TZPostgreSQLDatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string;
2172 const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet;
2175 SQL, Column, Owner: string;
2176 Privileges, Grantable, Grantee: string;
2177 Permissions, PermissionsExp: TStrings;
2178 ColumnNameCondition, TableNameCondition, SchemaCondition: string;
2180 SchemaCondition := ConstructNameCondition(Schema,'n.nspname');
2181 TableNameCondition := ConstructNameCondition(Table,'c.relname');
2182 ColumnNameCondition := ConstructNameCondition(ColumnNamePattern,'a.attname');
2183 Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern);
2185 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
2187 SQL := 'SELECT n.nspname,c.relname,u.usename,c.relacl,a.attname '
2188 + ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class c,'
2189 + ' pg_catalog.pg_user u, pg_catalog.pg_attribute a '
2190 + ' WHERE c.relnamespace = n.oid AND u.usesysid = c.relowner '
2191 + ' AND c.oid = a.attrelid AND c.relkind = ''r'''
2192 + ' AND a.attnum > 0 AND NOT a.attisdropped';
2193 if Schema <> '' then
2194 SQL := SQL + ' AND ' + SchemaCondition;
2198 SQL := 'SELECT NULL::text AS nspname,c.relname,u.usename,c.relacl,'
2199 + 'a.attname FROM pg_class c, pg_user u,pg_attribute a '
2200 + ' WHERE u.usesysid = c.relowner AND c.oid = a.attrelid '
2201 + ' AND a.attnum > 0 AND c.relkind = ''r''';
2204 If TableNameCondition <> '' then
2205 SQL := SQL + ' AND ' + TableNameCondition;
2206 If ColumnNameCondition <> '' then
2207 SQL := SQL + ' AND '+ ColumnNameCondition;
2208 SQL := SQL + ' ORDER BY attname';
2210 Permissions := TStringList.Create;
2211 PermissionsExp := TStringList.Create;
2213 with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2217 //SchemaName := GetStringByName('nspname');
2218 //TableName := GetStringByName('relname');
2219 Column := GetStringByName('attname');
2220 Owner := GetStringByName('usename');
2222 ParseACLArray(Permissions, GetStringByName('relacl'));
2223 for I := 0 to Permissions.Count-1 do
2225 PutSplitString(PermissionsExp, Permissions.Strings[I], '=');
2226 if PermissionsExp.Count < 2 then
2228 Grantee := PermissionsExp.Strings[0];
2229 if Grantee = '' then
2230 Grantee := 'PUBLIC';
2231 Privileges := PermissionsExp.Strings[1];
2232 for J := 1 to Length(Privileges) do
2234 if Owner = Grantee then
2236 else Grantable := 'NO';
2237 Result.MoveToInsertRow;
2238 Result.UpdateNull(1);
2239 Result.UpdateString(2, Schema);
2240 Result.UpdateString(3, Table);
2241 Result.UpdateString(4, Column);
2242 Result.UpdateString(5, Owner);
2243 Result.UpdateString(6, Grantee);
2244 Result.UpdateString(7, GetPrivilegeName(Privileges[J]));
2245 Result.UpdateString(8, grantable);
2254 PermissionsExp.Free;
2259 Gets a description of the access rights for each table available
2260 in a catalog. Note that a table privilege applies to one or
2261 more columns in the table. It would be wrong to assume that
2262 this priviledge applies to all columns (this may be true for
2263 some systems but is not true for all.)
2265 <P>Only privileges matching the schema and table name
2266 criteria are returned. They are ordered by TABLE_SCHEM,
2267 TABLE_NAME, and PRIVILEGE.
2269 <P>Each privilige description has the following columns:
2271 <LI><B>TABLE_CAT</B> String => table catalog (may be null)
2272 <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
2273 <LI><B>TABLE_NAME</B> String => table name
2274 <LI><B>GRANTOR</B> => grantor of access (may be null)
2275 <LI><B>GRANTEE</B> String => grantee of access
2276 <LI><B>PRIVILEGE</B> String => name of access (SELECT,
2277 INSERT, UPDATE, REFRENCES, ...)
2278 <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
2279 to grant to others; "NO" if not; null if unknown
2282 @param catalog a catalog name; "" retrieves those without a
2283 catalog; null means drop catalog name from the selection criteria
2284 @param schemaPattern a schema name pattern; "" retrieves those
2286 @param tableNamePattern a table name pattern
2287 @return <code>ResultSet</code> - each row is a table privilege description
2288 @see #getSearchStringEscape
2290 function TZPostgreSQLDatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string;
2291 const SchemaPattern: string; const TableNamePattern: string): IZResultSet;
2294 SQL, SchemaName, TableName, Owner: string;
2295 Privileges, Grantable, Grantee: string;
2296 Permissions, PermissionsExp: TStringList;
2297 TableNameCondition, SchemaCondition: string;
2299 SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname');
2300 TableNameCondition := ConstructNameCondition(TableNamePattern,'c.relname');
2301 Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern);
2303 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
2305 SQL := 'SELECT n.nspname,c.relname,u.usename,c.relacl '
2306 + ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class c,'
2307 + ' pg_catalog.pg_user u WHERE c.relnamespace = n.oid '
2308 + ' AND u.usesysid = c.relowner AND c.relkind = ''r'' ';
2309 if SchemaPattern <> '' then
2310 SQL := SQL + ' AND ' + SchemaCondition;
2314 SQL := 'SELECT NULL::text AS nspname,c.relname,u.usename,c.relacl '
2315 + ' FROM pg_class c, pg_user u WHERE u.usesysid = c.relowner '
2316 + ' AND c.relkind = ''r'' ';
2319 SQL := SQL + ' AND ' + TableNameCondition
2320 + ' ORDER BY nspname, relname';
2322 Permissions := TStringList.Create;
2323 PermissionsExp := TStringList.Create;
2325 with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2329 SchemaName := GetStringByName('nspname');
2330 TableName := GetStringByName('relname');
2331 Owner := GetStringByName('usename');
2332 SchemaName := GetStringByName('nspname');
2334 ParseACLArray(Permissions, GetStringByName('relacl'));
2336 for I := 0 to Permissions.Count-1 do
2338 PutSplitString(PermissionsExp, Permissions.Strings[I], '=');
2339 if PermissionsExp.Count < 2 then
2341 Grantee := PermissionsExp.Strings[0];
2342 if Grantee = '' then
2343 Grantee := 'PUBLIC';
2344 Privileges := PermissionsExp.Strings[1];
2345 for J := 1 to Length(Privileges) do
2347 if Owner = Grantee then
2349 else Grantable := 'NO';
2350 Result.MoveToInsertRow;
2351 Result.UpdateNull(1);
2352 Result.UpdateString(2, SchemaName);
2353 Result.UpdateString(3, TableName);
2354 Result.UpdateString(4, Owner);
2355 Result.UpdateString(5, Grantee);
2356 Result.UpdateString(6, GetPrivilegeName(Privileges[J]));
2357 Result.UpdateString(7, grantable);
2366 PermissionsExp.Free;
2371 Gets a description of a table's columns that are automatically
2372 updated when any value in a row is updated. They are
2375 <P>Each column description has the following columns:
2377 <LI><B>SCOPE</B> short => is not used
2378 <LI><B>COLUMN_NAME</B> String => column name
2379 <LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
2380 <LI><B>TYPE_NAME</B> String => Data source dependent type name
2381 <LI><B>COLUMN_SIZE</B> int => precision
2382 <LI><B>BUFFER_LENGTH</B> int => length of column value in bytes
2383 <LI><B>DECIMAL_DIGITS</B> short => scale
2384 <LI><B>PSEUDO_COLUMN</B> short => is this a pseudo column
2385 like an Oracle ROWID
2387 <LI> versionColumnUnknown - may or may not be pseudo column
2388 <LI> versionColumnNotPseudo - is NOT a pseudo column
2389 <LI> versionColumnPseudo - is a pseudo column
2393 @param catalog a catalog name; "" retrieves those without a
2394 catalog; null means drop catalog name from the selection criteria
2395 @param schema a schema name; "" retrieves those without a schema
2396 @param table a table name
2397 @return <code>ResultSet</code> - each row is a column description
2398 @exception SQLException if a database access error occurs
2400 function TZPostgreSQLDatabaseMetadata.UncachedGetVersionColumns(const Catalog: string;
2401 const Schema: string; const Table: string): IZResultSet;
2403 Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table);
2405 Result.MoveToInsertRow;
2406 Result.UpdateNull(1);
2407 Result.UpdateString(2, 'ctid');
2408 Result.UpdateInt(3, Ord(GetSQLTypeByName('tid')));
2409 Result.UpdateString(4, 'tid');
2410 Result.UpdateNull(5);
2411 Result.UpdateNull(6);
2412 Result.UpdateNull(7);
2413 Result.UpdateInt(4, Ord(vcPseudo));
2418 Gets a description of a table's primary key columns. They
2419 are ordered by COLUMN_NAME.
2421 <P>Each primary key column description has the following columns:
2423 <LI><B>TABLE_CAT</B> String => table catalog (may be null)
2424 <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
2425 <LI><B>TABLE_NAME</B> String => table name
2426 <LI><B>COLUMN_NAME</B> String => column name
2427 <LI><B>KEY_SEQ</B> short => sequence number within primary key
2428 <LI><B>PK_NAME</B> String => primary key name (may be null)
2431 @param catalog a catalog name; "" retrieves those without a
2432 catalog; null means drop catalog name from the selection criteria
2433 @param schema a schema name; "" retrieves those
2435 @param table a table name
2436 @return <code>ResultSet</code> - each row is a primary key column description
2437 @exception SQLException if a database access error occurs
2439 function TZPostgreSQLDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string;
2440 const Schema: string; const Table: string): IZResultSet;
2442 SQL, Select, From, Where: string;
2443 TableNameCondition, SchemaCondition: string;
2445 SchemaCondition := ConstructNameCondition(Schema,'n.nspname');
2446 TableNameCondition := ConstructNameCondition(Table,'ct.relname');
2447 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
2449 Select := 'SELECT NULL AS TABLE_CAT, n.nspname AS TABLE_SCHEM,';
2450 From := ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class ct,'
2451 + ' pg_catalog.pg_class ci, pg_catalog.pg_attribute a,'
2452 + ' pg_catalog.pg_index i';
2453 Where := ' AND ct.relnamespace = n.oid';
2454 if Schema <> '' then
2455 Where := Where + ' AND ' + SchemaCondition;
2459 Select := 'SELECT NULL AS TABLE_CAT, NULL AS TABLE_SCHEM,';
2460 From := ' FROM pg_class ct, pg_class ci, pg_attribute a, pg_index i';
2462 SQL := Select + ' ct.relname AS TABLE_NAME, a.attname AS COLUMN_NAME,'
2463 + ' a.attnum AS KEY_SEQ, ci.relname AS PK_NAME'
2465 + ' WHERE ct.oid=i.indrelid AND ci.oid=i.indexrelid'
2466 + ' AND a.attrelid=ci.oid AND i.indisprimary';
2468 SQL := SQL + ' AND ' + TableNameCondition;
2469 SQL := SQL + Where + ' ORDER BY table_name, pk_name, key_seq';
2471 Result := CopyToVirtualResultSet(
2472 GetConnection.CreateStatement.ExecuteQuery(SQL),
2473 ConstructVirtualResultSet(PrimaryKeyColumnsDynArray));
2477 Gets a description of the primary key columns that are
2478 referenced by a table's foreign key columns (the primary keys
2479 imported by a table). They are ordered by PKTABLE_CAT,
2480 PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
2482 <P>Each primary key column description has the following columns:
2484 <LI><B>PKTABLE_CAT</B> String => primary key table catalog
2485 being imported (may be null)
2486 <LI><B>PKTABLE_SCHEM</B> String => primary key table schema
2487 being imported (may be null)
2488 <LI><B>PKTABLE_NAME</B> String => primary key table name
2490 <LI><B>PKCOLUMN_NAME</B> String => primary key column name
2492 <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
2493 <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
2494 <LI><B>FKTABLE_NAME</B> String => foreign key table name
2495 <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
2496 <LI><B>KEY_SEQ</B> short => sequence number within foreign key
2497 <LI><B>UPDATE_RULE</B> short => What happens to
2498 foreign key when primary is updated:
2500 <LI> importedNoAction - do not allow update of primary
2501 key if it has been imported
2502 <LI> importedKeyCascade - change imported key to agree
2503 with primary key update
2504 <LI> importedKeySetNull - change imported key to NULL if
2505 its primary key has been updated
2506 <LI> importedKeySetDefault - change imported key to default values
2507 if its primary key has been updated
2508 <LI> importedKeyRestrict - same as importedKeyNoAction
2509 (for ODBC 2.x compatibility)
2511 <LI><B>DELETE_RULE</B> short => What happens to
2512 the foreign key when primary is deleted.
2514 <LI> importedKeyNoAction - do not allow delete of primary
2515 key if it has been imported
2516 <LI> importedKeyCascade - delete rows that import a deleted key
2517 <LI> importedKeySetNull - change imported key to NULL if
2518 its primary key has been deleted
2519 <LI> importedKeyRestrict - same as importedKeyNoAction
2520 (for ODBC 2.x compatibility)
2521 <LI> importedKeySetDefault - change imported key to default if
2522 its primary key has been deleted
2524 <LI><B>FK_NAME</B> String => foreign key name (may be null)
2525 <LI><B>PK_NAME</B> String => primary key name (may be null)
2526 <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
2527 constraints be deferred until commit
2529 <LI> importedKeyInitiallyDeferred - see SQL92 for definition
2530 <LI> importedKeyInitiallyImmediate - see SQL92 for definition
2531 <LI> importedKeyNotDeferrable - see SQL92 for definition
2535 @param catalog a catalog name; "" retrieves those without a
2536 catalog; null means drop catalog name from the selection criteria
2537 @param schema a schema name; "" retrieves those
2539 @param table a table name
2540 @return <code>ResultSet</code> - each row is a primary key column description
2541 @see #getExportedKeys
2543 function TZPostgreSQLDatabaseMetadata.UncachedGetImportedKeys(const Catalog: string;
2544 const Schema: string; const Table: string): IZResultSet;
2547 KeySequence: Integer;
2548 TableNameCondition, SchemaCondition, CatalogCondition: string;
2550 CatalogCondition := ConstructNameCondition(Catalog,'kcu.table_catalog');
2551 SchemaCondition := ConstructNameCondition(Schema,'kcu.constraint_schema');
2552 TableNameCondition := ConstructNameCondition(Table,'kcu.table_name');
2553 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 4) then
2555 Result:=inherited UncachedGetImportedKeys(Catalog, Schema, Table);
2557 'tc.constraint_catalog as PKTABLE_CAT, '+
2558 'tc.constraint_schema as PKTABLE_SCHEM, '+
2559 'ccu.table_name as PKTABLE_NAME, '+
2560 'ccu.column_name as PKCOLUMN_NAME, '+
2561 'kcu.table_catalog as FKTABLE_CAT, '+
2562 'kcu.constraint_schema as FKTABLE_SCHEM, '+
2563 'kcu.table_name as PKTABLE_NAME, '+
2564 'kcu.column_name as FKCOLUMN_NAME, '+
2565 'rf.update_rule as UPDATE_RULE, '+
2566 'rf.delete_rule as DELETE_RULE, '+
2567 'kcu.constraint_name as FK_NAME, '+
2568 'kcu.ordinal_position as PK_NAME, '+
2569 'tc.is_deferrable as DEFERRABILITY '+
2570 'FROM information_schema.table_constraints AS tc '+
2571 'JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name '+
2572 'JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name '+
2573 'join information_schema.referential_constraints as rf on rf.constraint_name = tc.constraint_name '+
2574 'WHERE constraint_type = ''FOREIGN KEY''';
2575 if Catalog <> '' then
2576 SQL := SQL + ' and ' + CatalogCondition;
2577 if Schema <> '' then
2578 SQL := SQL + ' and ' + SchemaCondition;
2580 SQL := SQL + ' and ' + TableNameCondition;
2583 with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2588 Result.MoveToInsertRow;
2589 Result.UpdateNull(1); //PKTABLE_CAT
2590 Result.UpdateString(2, GetString(2)); //PKTABLE_SCHEM
2591 Result.UpdateString(3, GetString(3)); //PKTABLE_NAME
2592 Result.UpdateString(4, GetString(4)); //PKCOLUMN_NAME
2593 //Result.UpdateString(5, GetString(5)); //PKTABLE_CAT
2594 Result.UpdateString(5, Catalog); //PKTABLE_CAT
2595 Result.UpdateString(6, GetString(6)); //FKTABLE_SCHEM
2596 Result.UpdateString(7, GetString(7)); //FKTABLE_NAME
2597 Result.UpdateString(8, GetString(8)); //FKCOLUMN_NAME
2598 Result.UpdateShort(9, KeySequence); //KEY_SEQ
2599 Result.UpdateShort(10, Ord(GetRuleType(GetString(9)))); //UPDATE_RULE
2600 Result.UpdateShort(11, Ord(GetRuleType(GetString(10)))); //DELETE_RULE
2601 Result.UpdateString(12, GetString(11)); //FK_NAME
2602 Result.UpdateString(13, GetString(12)); //PK_NAME
2603 if GetString(13) = 'NO' then
2604 Result.UpdateShort(14, Ord(ikNotDeferrable)) //DEFERRABILITY
2606 Result.UpdateShort(14, Ord(ikInitiallyDeferred)); //DEFERRABILITY
2613 Result := UncachedGetCrossReference('', '', '', Catalog, Schema, Table);
2617 Gets a description of the foreign key columns that reference a
2618 table's primary key columns (the foreign keys exported by a
2619 table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
2620 FKTABLE_NAME, and KEY_SEQ.
2622 <P>Each foreign key column description has the following columns:
2624 <LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
2625 <LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
2626 <LI><B>PKTABLE_NAME</B> String => primary key table name
2627 <LI><B>PKCOLUMN_NAME</B> String => primary key column name
2628 <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
2629 being exported (may be null)
2630 <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
2631 being exported (may be null)
2632 <LI><B>FKTABLE_NAME</B> String => foreign key table name
2634 <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
2636 <LI><B>KEY_SEQ</B> short => sequence number within foreign key
2637 <LI><B>UPDATE_RULE</B> short => What happens to
2638 foreign key when primary is updated:
2640 <LI> importedNoAction - do not allow update of primary
2641 key if it has been imported
2642 <LI> importedKeyCascade - change imported key to agree
2643 with primary key update
2644 <LI> importedKeySetNull - change imported key to NULL if
2645 its primary key has been updated
2646 <LI> importedKeySetDefault - change imported key to default values
2647 if its primary key has been updated
2648 <LI> importedKeyRestrict - same as importedKeyNoAction
2649 (for ODBC 2.x compatibility)
2651 <LI><B>DELETE_RULE</B> short => What happens to
2652 the foreign key when primary is deleted.
2654 <LI> importedKeyNoAction - do not allow delete of primary
2655 key if it has been imported
2656 <LI> importedKeyCascade - delete rows that import a deleted key
2657 <LI> importedKeySetNull - change imported key to NULL if
2658 its primary key has been deleted
2659 <LI> importedKeyRestrict - same as importedKeyNoAction
2660 (for ODBC 2.x compatibility)
2661 <LI> importedKeySetDefault - change imported key to default if
2662 its primary key has been deleted
2664 <LI><B>FK_NAME</B> String => foreign key name (may be null)
2665 <LI><B>PK_NAME</B> String => primary key name (may be null)
2666 <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
2667 constraints be deferred until commit
2669 <LI> importedKeyInitiallyDeferred - see SQL92 for definition
2670 <LI> importedKeyInitiallyImmediate - see SQL92 for definition
2671 <LI> importedKeyNotDeferrable - see SQL92 for definition
2675 @param catalog a catalog name; "" retrieves those without a
2676 catalog; null means drop catalog name from the selection criteria
2677 @param schema a schema name; "" retrieves those
2679 @param table a table name
2680 @return <code>ResultSet</code> - each row is a foreign key column description
2681 @see #getImportedKeys
2683 function TZPostgreSQLDatabaseMetadata.UncachedGetExportedKeys(const Catalog: string;
2684 const Schema: string; const Table: string): IZResultSet;
2687 KeySequence: Integer;
2688 TableNameCondition, SchemaCondition, CatalogCondition: string;
2690 CatalogCondition := ConstructNameCondition(Catalog,'tc.constraint_catalog');
2691 SchemaCondition := ConstructNameCondition(Schema,'tc.constraint_schema');
2692 TableNameCondition := ConstructNameCondition(Table,'ccu.table_name');
2693 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 4) then
2695 Result:=inherited UncachedGetImportedKeys(Catalog, Schema, Table);
2697 'tc.constraint_catalog as PKTABLE_CAT, '+
2698 'tc.constraint_schema as PKTABLE_SCHEM, '+
2699 'ccu.table_name as PKTABLE_NAME, '+
2700 'ccu.column_name as PKCOLUMN_NAME, '+
2701 'kcu.table_catalog as FKTABLE_CAT, '+
2702 'kcu.constraint_schema as FKTABLE_SCHEM, '+
2703 'kcu.table_name as PKTABLE_NAME, '+
2704 'kcu.column_name as FKCOLUMN_NAME, '+
2705 'rf.update_rule as UPDATE_RULE, '+
2706 'rf.delete_rule as DELETE_RULE, '+
2707 'kcu.constraint_name as FK_NAME, '+
2708 'kcu.ordinal_position as PK_NAME, '+
2709 'tc.is_deferrable as DEFERRABILITY '+
2710 'FROM information_schema.table_constraints AS tc '+
2711 'JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name '+
2712 'JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name '+
2713 'join information_schema.referential_constraints as rf on rf.constraint_name = tc.constraint_name '+
2714 'WHERE constraint_type = ''FOREIGN KEY''';
2715 if Catalog <> '' then
2716 SQL := SQL + ' and ' + CatalogCondition;
2717 if Schema <> '' then
2718 SQL := SQL + ' and ' + SchemaCondition;
2720 SQL := SQL + ' and ' + TableNameCondition;
2721 SQL := SQL + ' order by kcu.table_name;';
2724 with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2729 Result.MoveToInsertRow;
2730 Result.UpdateNull(1); //PKTABLE_CAT
2731 Result.UpdateString(2, GetString(2)); //PKTABLE_SCHEM
2732 Result.UpdateString(3, GetString(3)); //PKTABLE_NAME
2733 Result.UpdateString(4, GetString(4)); //PKCOLUMN_NAME
2734 //Result.UpdateString(5, GetString(5)); //PKTABLE_CAT
2735 Result.UpdateString(5, Catalog); //PKTABLE_CAT
2736 Result.UpdateString(6, GetString(6)); //FKTABLE_SCHEM
2737 Result.UpdateString(7, GetString(7)); //FKTABLE_NAME
2738 Result.UpdateString(8, GetString(8)); //FKCOLUMN_NAME
2739 Result.UpdateShort(9, KeySequence); //KEY_SEQ
2740 Result.UpdateShort(10, Ord(GetRuleType(GetString(9)))); //UPDATE_RULE
2741 Result.UpdateShort(11, Ord(GetRuleType(GetString(10)))); //DELETE_RULE
2742 Result.UpdateString(12, GetString(11)); //FK_NAME
2743 Result.UpdateString(13, GetString(12)); //PK_NAME
2744 if GetString(13) = 'NO' then
2745 Result.UpdateShort(14, Ord(ikNotDeferrable)) //DEFERRABILITY
2747 Result.UpdateShort(14, Ord(ikInitiallyDeferred)); //DEFERRABILITY
2754 Result := UncachedGetCrossReference('', '', '', Catalog, Schema, Table);
2758 Gets a description of the foreign key columns in the foreign key
2759 table that reference the primary key columns of the primary key
2760 table (describe how one table imports another's key.) This
2761 should normally return a single foreign key/primary key pair
2762 (most tables only import a foreign key from a table once.) They
2763 are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and
2766 <P>Each foreign key column description has the following columns:
2768 <LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
2769 <LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
2770 <LI><B>PKTABLE_NAME</B> String => primary key table name
2771 <LI><B>PKCOLUMN_NAME</B> String => primary key column name
2772 <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
2773 being exported (may be null)
2774 <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
2775 being exported (may be null)
2776 <LI><B>FKTABLE_NAME</B> String => foreign key table name
2778 <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
2780 <LI><B>KEY_SEQ</B> short => sequence number within foreign key
2781 <LI><B>UPDATE_RULE</B> short => What happens to
2782 foreign key when primary is updated:
2784 <LI> importedNoAction - do not allow update of primary
2785 key if it has been imported
2786 <LI> importedKeyCascade - change imported key to agree
2787 with primary key update
2788 <LI> importedKeySetNull - change imported key to NULL if
2789 its primary key has been updated
2790 <LI> importedKeySetDefault - change imported key to default values
2791 if its primary key has been updated
2792 <LI> importedKeyRestrict - same as importedKeyNoAction
2793 (for ODBC 2.x compatibility)
2795 <LI><B>DELETE_RULE</B> short => What happens to
2796 the foreign key when primary is deleted.
2798 <LI> importedKeyNoAction - do not allow delete of primary
2799 key if it has been imported
2800 <LI> importedKeyCascade - delete rows that import a deleted key
2801 <LI> importedKeySetNull - change imported key to NULL if
2802 its primary key has been deleted
2803 <LI> importedKeyRestrict - same as importedKeyNoAction
2804 (for ODBC 2.x compatibility)
2805 <LI> importedKeySetDefault - change imported key to default if
2806 its primary key has been deleted
2808 <LI><B>FK_NAME</B> String => foreign key name (may be null)
2809 <LI><B>PK_NAME</B> String => primary key name (may be null)
2810 <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
2811 constraints be deferred until commit
2813 <LI> importedKeyInitiallyDeferred - see SQL92 for definition
2814 <LI> importedKeyInitiallyImmediate - see SQL92 for definition
2815 <LI> importedKeyNotDeferrable - see SQL92 for definition
2819 @param primaryCatalog a catalog name; "" retrieves those without a
2820 catalog; null means drop catalog name from the selection criteria
2821 @param primarySchema a schema name; "" retrieves those
2823 @param primaryTable the table name that exports the key
2824 @param foreignCatalog a catalog name; "" retrieves those without a
2825 catalog; null means drop catalog name from the selection criteria
2826 @param foreignSchema a schema name; "" retrieves those
2828 @param foreignTable the table name that imports the key
2829 @return <code>ResultSet</code> - each row is a foreign key column description
2830 @see #getImportedKeys
2832 function TZPostgreSQLDatabaseMetadata.UncachedGetCrossReference(const PrimaryCatalog: string;
2833 const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string;
2834 const ForeignSchema: string; const ForeignTable: string): IZResultSet;
2836 SQL, Select, From, Where: string;
2837 DeleteRule, UpdateRule, Rule: string;
2838 {FKeyName, }FKeyColumn, PKeyColumn, Targs: string;
2839 Action, KeySequence, Advance: Integer;
2841 Deferrability: Integer;
2842 Deferrable, InitiallyDeferred: Boolean;
2844 Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable,
2845 ForeignCatalog, ForeignSchema, ForeignTable);
2847 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 4) then
2850 'tc.constraint_catalog as PKTABLE_CAT, '+
2851 'tc.constraint_schema as PKTABLE_SCHEM, '+
2852 'ccu.table_name as PKTABLE_NAME, '+
2853 'ccu.column_name as PKCOLUMN_NAME, '+
2854 'kcu.table_catalog as FKTABLE_CAT, '+
2855 'kcu.constraint_schema as FKTABLE_SCHEM, '+
2856 'kcu.table_name as PKTABLE_NAME, '+
2857 'kcu.column_name as FKCOLUMN_NAME, '+
2858 'rf.update_rule as UPDATE_RULE, '+
2859 'rf.delete_rule as DELETE_RULE, '+
2860 'kcu.constraint_name as FK_NAME, '+
2861 'kcu.ordinal_position as PK_NAME, '+
2862 'tc.is_deferrable as DEFERRABILITY '+
2863 'FROM information_schema.table_constraints AS tc '+
2864 'JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name '+
2865 'JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name '+
2866 'join information_schema.referential_constraints as rf on rf.constraint_name = tc.constraint_name '+
2867 'WHERE constraint_type = ''FOREIGN KEY''';
2868 if PrimaryCatalog <> '' then
2869 SQL := SQL + ' and tc.constraint_catalog = '''+PrimaryCatalog+'''';
2870 if PrimarySchema <> '' then
2871 SQL := SQL + ' and tc.constraint_schema = '''+PrimarySchema+'''';
2872 if PrimaryTable <> '' then
2873 SQL := SQL + ' and ccu.table_name = '''+PrimaryTable+'''';
2874 if ForeignCatalog <> '' then
2875 SQL := SQL + ' and kcu.table_catalog = '''+ForeignCatalog+'''';
2876 if ForeignSchema <> '' then
2877 SQL := SQL + ' and kcu.constraint_schema = '''+ForeignSchema+'''';
2878 if ForeignTable <> '' then
2879 SQL := SQL + ' and kcu.table_name = '''+ForeignTable+'''';
2882 with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2887 Result.MoveToInsertRow;
2888 //Result.UpdateString(1, GetString(1)); //PKTABLE_CAT
2889 Result.UpdateString(1, PrimaryCatalog); //PKTABLE_CAT
2890 Result.UpdateString(2, GetString(2)); //PKTABLE_SCHEM
2891 Result.UpdateString(3, GetString(3)); //PKTABLE_NAME
2892 Result.UpdateString(4, GetString(4)); //PKCOLUMN_NAME
2893 //Result.UpdateString(5, GetString(5)); //PKTABLE_CAT
2894 Result.UpdateString(5, ForeignCatalog); //PKTABLE_CAT
2895 Result.UpdateString(6, GetString(6)); //FKTABLE_SCHEM
2896 Result.UpdateString(7, GetString(7)); //FKTABLE_NAME
2897 Result.UpdateString(8, GetString(8)); //FKCOLUMN_NAME
2898 Result.UpdateShort(9, KeySequence); //KEY_SEQ
2899 Result.UpdateShort(10, Ord(GetRuleType(GetString(9)))); //UPDATE_RULE
2900 Result.UpdateShort(11, Ord(GetRuleType(GetString(10)))); //DELETE_RULE
2901 Result.UpdateString(12, GetString(11)); //FK_NAME
2902 Result.UpdateString(13, GetString(12)); //PK_NAME
2903 if GetString(13) = 'NO' then
2904 Result.UpdateShort(14, Ord(ikNotDeferrable)) //DEFERRABILITY
2906 Result.UpdateShort(14, Ord(ikInitiallyDeferred)); //DEFERRABILITY
2914 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
2916 Select := 'SELECT DISTINCT n1.nspname as pnspname,n2.nspname as fnspname,';
2917 From := ' FROM pg_catalog.pg_namespace n1 JOIN pg_catalog.pg_class c1'
2918 + ' ON (c1.relnamespace = n1.oid) JOIN pg_catalog.pg_index i'
2919 + ' ON (c1.oid=i.indrelid) JOIN pg_catalog.pg_class ic'
2920 + ' ON (i.indexrelid=ic.oid) JOIN pg_catalog.pg_attribute a'
2921 + ' ON (ic.oid=a.attrelid), pg_catalog.pg_namespace n2'
2922 + ' JOIN pg_catalog.pg_class c2 ON (c2.relnamespace=n2.oid),'
2923 + ' pg_catalog.pg_trigger t1 JOIN pg_catalog.pg_proc p1'
2924 + ' ON (t1.tgfoid=p1.oid), pg_catalog.pg_trigger t2'
2925 + ' JOIN pg_catalog.pg_proc p2 ON (t2.tgfoid=p2.oid)';
2927 if PrimarySchema <> ''then
2929 Where := Where + ' AND n1.nspname = '
2930 + EscapeString(PrimarySchema);
2932 if ForeignSchema <> '' then
2934 Where := Where + ' AND n2.nspname = '
2935 + EscapeString(ForeignSchema);
2940 Select := 'SELECT DISTINCT NULL::text as pnspname, NULL::text as fnspname,';
2941 From := ' FROM pg_class c1 JOIN pg_index i ON (c1.oid=i.indrelid)'
2942 + ' JOIN pg_class ic ON (i.indexrelid=ic.oid) JOIN pg_attribute a'
2943 + ' ON (ic.oid=a.attrelid), pg_class c2, pg_trigger t1'
2944 + ' JOIN pg_proc p1 ON (t1.tgfoid=p1.oid), pg_trigger t2'
2945 + ' JOIN pg_proc p2 ON (t2.tgfoid=p2.oid)';
2948 SQL := Select + ' c1.relname as prelname, c2.relname as frelname,'
2949 + ' t1.tgconstrname, a.attnum as keyseq, ic.relname as fkeyname,'
2950 + ' t1.tgdeferrable, t1.tginitdeferred, t1.tgnargs,t1.tgargs,'
2951 + ' p1.proname as updaterule, p2.proname as deleterule'
2953 + ' WHERE (t1.tgrelid=c1.oid AND t1.tgisconstraint'
2954 + ' AND t1.tgconstrrelid=c2.oid AND p1.proname'
2955 + ' LIKE ' + EscapeString('RI\_FKey\_%\_upd')
2956 + ') AND (t2.tgrelid=c1.oid'
2957 + ' AND t2.tgisconstraint AND t2.tgconstrrelid=c2.oid '
2958 + ' AND p2.proname LIKE ' + EscapeString('RI\_FKey\_%\_del')
2959 + ') AND i.indisprimary'
2961 if PrimaryTable <> '' then
2962 SQL := SQL + ' AND c1.relname=' + EscapeString(PrimaryTable);
2963 if ForeignTable <> '' then
2964 SQL := SQL + ' AND c2.relname=' + EscapeString(ForeignTable);
2965 SQL := SQL + ' ORDER BY ';
2967 if PrimaryTable <> '' then
2969 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
2970 SQL := SQL + 'fnspname, ';
2971 SQL := SQL + 'frelname';
2975 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
2976 SQL := SQL + 'pnspname, ';
2977 SQL := SQL + 'prelname';
2980 SQL := SQL + ', keyseq';
2982 List := TStringList.Create;
2984 with GetConnection.CreateStatement.ExecuteQuery(SQL) do
2988 Result.MoveToInsertRow;
2989 Result.UpdateString(2, GetString(1));
2990 Result.UpdateString(6, GetString(2));
2991 Result.UpdateString(3, GetString(3));
2992 Result.UpdateString(7, GetString(4));
2994 //FKeyName := GetString(5);
2995 UpdateRule := GetString(12);
2996 if UpdateRule <> '' then
2998 Rule := Copy(UpdateRule, 9, Length(UpdateRule) - 12);
2999 Action := Ord(ikNoAction);
3000 if (Rule = '') or (Rule = 'noaction') then
3001 Action := Ord(ikNoAction);
3002 if Rule = 'cascade' then
3003 Action := Ord(ikCascade);
3004 if Rule = 'setnull' then
3005 Action := Ord(ikSetNull);
3006 if Rule = 'setdefault' then
3007 Action := Ord(ikSetDefault);
3008 if Rule = 'restrict' then
3009 Action := Ord(ikRestrict);
3010 Result.UpdateInt(10, Action);
3013 DeleteRule := GetString(13);
3014 if DeleteRule <> '' then
3016 Rule := Copy(DeleteRule, 9, Length(DeleteRule) - 12);
3017 Action := Ord(ikNoAction);
3018 if Rule = 'cascade' then
3019 Action := Ord(ikCascade);
3020 if Rule = 'setnull' then
3021 Action := Ord(ikSetNull);
3022 if Rule = 'setdefault' then
3023 Action := Ord(ikSetDefault);
3024 if Rule = 'restrict' then
3025 Action := Ord(ikRestrict);
3026 Result.UpdateInt(11, Action);
3029 KeySequence := GetInt(6);
3030 Targs := GetString(11);
3032 //<unnamed>\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000
3033 //for Postgresql 7.3
3034 //$1\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000
3035 //$2\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000
3037 Advance := 4 + (KeySequence - 1) * 2;
3038 PutSplitStringEx(List, Targs, '\000');
3040 if Advance <= List.Count-1 then
3041 FKeyColumn := List.Strings[Advance];
3042 if Advance + 1 <= List.Count-1 then
3043 PKeyColumn := List.Strings[Advance+1];
3044 Result.UpdateString(4, PKeyColumn);
3045 Result.UpdateString(8, FKeyColumn);
3046 Result.UpdateString(9, GetString(6)); //KEY_SEQ
3048 if List.Strings[0] = '<unnamed>' then
3049 Result.UpdateString(12, Targs) //FK_NAME
3050 else Result.UpdateString(12, List.Strings[0]); //FK_NAME
3052 Result.UpdateString(13, GetString(6)); //PK_ NAME
3054 Deferrability := Ord(ikNotDeferrable);
3055 Deferrable := GetBoolean(8);
3056 InitiallyDeferred := GetBoolean(9);
3059 if InitiallyDeferred then
3060 Deferrability := Ord(ikInitiallyDeferred)
3061 else Deferrability := Ord(ikInitiallyImmediate);
3063 Result.UpdateInt(14, Deferrability);
3075 Gets a description of all the standard SQL types supported by
3076 this database. They are ordered by DATA_TYPE and then by how
3077 closely the data type maps to the corresponding JDBC SQL type.
3079 <P>Each type description has the following columns:
3081 <LI><B>TYPE_NAME</B> String => Type name
3082 <LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
3083 <LI><B>PRECISION</B> int => maximum precision
3084 <LI><B>LITERAL_PREFIX</B> String => prefix used to quote a literal
3086 <LI><B>LITERAL_SUFFIX</B> String => suffix used to quote a literal
3088 <LI><B>CREATE_PARAMS</B> String => parameters used in creating
3089 the type (may be null)
3090 <LI><B>NULLABLE</B> short => can you use NULL for this type?
3092 <LI> typeNoNulls - does not allow NULL values
3093 <LI> typeNullable - allows NULL values
3094 <LI> typeNullableUnknown - nullability unknown
3096 <LI><B>CASE_SENSITIVE</B> Boolean=> is it case sensitive?
3097 <LI><B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
3099 <LI> typePredNone - No support
3100 <LI> typePredChar - Only supported with WHERE .. LIKE
3101 <LI> typePredBasic - Supported except for WHERE .. LIKE
3102 <LI> typeSearchable - Supported for all WHERE ..
3104 <LI><B>UNSIGNED_ATTRIBUTE</B> Boolean => is it unsigned?
3105 <LI><B>FIXED_PREC_SCALE</B> Boolean => can it be a money value?
3106 <LI><B>AUTO_INCREMENT</B> Boolean => can it be used for an
3107 auto-increment value?
3108 <LI><B>LOCAL_TYPE_NAME</B> String => localized version of type name
3110 <LI><B>MINIMUM_SCALE</B> short => minimum scale supported
3111 <LI><B>MAXIMUM_SCALE</B> short => maximum scale supported
3112 <LI><B>SQL_DATA_TYPE</B> int => unused
3113 <LI><B>SQL_DATETIME_SUB</B> int => unused
3114 <LI><B>NUM_PREC_RADIX</B> int => usually 2 or 10
3117 @return <code>ResultSet</code> - each row is an SQL type description
3119 function TZPostgreSQLDatabaseMetadata.UncachedGetTypeInfo: IZResultSet;
3123 Result:=inherited UncachedGetTypeInfo;
3125 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
3126 SQL := ' SELECT typname FROM pg_catalog.pg_type '
3127 else SQL := ' SELECT typname FROM pg_type ';
3129 with GetConnection.CreateStatement.ExecuteQuery(SQL) do
3133 Result.MoveToInsertRow;
3134 Result.UpdateString(1, GetString(1));
3135 Result.UpdateInt(2, Ord(GetSQLTypeByName(GetString(1))));
3136 Result.UpdateInt(3, 9);
3137 Result.UpdateInt(7, Ord(ntNoNulls));
3138 Result.UpdateBoolean(8, False);
3139 Result.UpdateBoolean(9, False);
3140 Result.UpdateBoolean(11, False);
3141 Result.UpdateBoolean(12, False);
3142 Result.UpdateInt(18, 10);
3150 Gets a description of a table's indices and statistics. They are
3151 ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
3153 <P>Each index column description has the following columns:
3155 <LI><B>TABLE_CAT</B> String => table catalog (may be null)
3156 <LI><B>TABLE_SCHEM</B> String => table schema (may be null)
3157 <LI><B>TABLE_NAME</B> String => table name
3158 <LI><B>NON_UNIQUE</B> Boolean => Can index values be non-unique?
3159 false when TYPE is tableIndexStatistic
3160 <LI><B>INDEX_QUALIFIER</B> String => index catalog (may be null);
3161 null when TYPE is tableIndexStatistic
3162 <LI><B>INDEX_NAME</B> String => index name; null when TYPE is
3164 <LI><B>TYPE</B> short => index type:
3166 <LI> tableIndexStatistic - this identifies table statistics that are
3167 returned in conjuction with a table's index descriptions
3168 <LI> tableIndexClustered - this is a clustered index
3169 <LI> tableIndexHashed - this is a hashed index
3170 <LI> tableIndexOther - this is some other style of index
3172 <LI><B>ORDINAL_POSITION</B> short => column sequence number
3173 within index; zero when TYPE is tableIndexStatistic
3174 <LI><B>COLUMN_NAME</B> String => column name; null when TYPE is
3176 <LI><B>ASC_OR_DESC</B> String => column sort sequence, "A" => ascending,
3177 "D" => descending, may be null if sort sequence is not supported;
3178 null when TYPE is tableIndexStatistic
3179 <LI><B>CARDINALITY</B> int => When TYPE is tableIndexStatistic, then
3180 this is the number of rows in the table; otherwise, it is the
3181 number of unique values in the index.
3182 <LI><B>PAGES</B> int => When TYPE is tableIndexStatisic then
3183 this is the number of pages used for the table, otherwise it
3184 is the number of pages used for the current index.
3185 <LI><B>FILTER_CONDITION</B> String => Filter condition, if any.
3189 @param catalog a catalog name; "" retrieves those without a
3190 catalog; null means drop catalog name from the selection criteria
3191 @param schema a schema name; "" retrieves those without a schema
3192 @param table a table name
3193 @param unique when true, return only indices for unique values;
3194 when false, return indices regardless of whether unique or not
3195 @param approximate when true, result is allowed to reflect approximate
3196 or out of data values; when false, results are requested to be
3198 @return <code>ResultSet</code> - each row is an index column description
3200 function TZPostgreSQLDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string;
3201 const Schema: string; const Table: string; Unique: Boolean;
3202 Approximate: Boolean): IZResultSet;
3204 SQL, Select, From, Where: string;
3206 if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then
3208 Select := 'SELECT NULL AS TABLE_CAT, n.nspname AS TABLE_SCHEM,';
3209 From := ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class ct,'
3210 + ' pg_catalog.pg_class ci, pg_catalog.pg_index i,'
3211 + ' pg_catalog.pg_attribute a, pg_catalog.pg_am am';
3212 Where := ' AND n.oid = ct.relnamespace';
3213 if Schema <> '' then
3214 Where := Where + ' AND n.nspname = ' + EscapeString(Schema);
3218 Select := 'SELECT NULL AS TABLE_CAT, NULL AS TABLE_SCHEM,';
3219 From := ' FROM pg_class ct, pg_class ci, pg_index i, pg_attribute a,'
3223 SQL := Select + ' ct.relname AS TABLE_NAME, NOT i.indisunique'
3224 + ' AS NON_UNIQUE, NULL AS INDEX_QUALIFIER, ci.relname AS INDEX_NAME,'
3225 + ' CASE i.indisclustered WHEN true THEN ' + IntToStr(Ord(tiClustered))
3226 + ' ELSE CASE am.amname WHEN ''hash'' THEN ' + IntToStr(Ord(tiHashed))
3227 + ' ELSE ' + IntToStr(Ord(tiOther)) + ' END END AS TYPE,'
3228 + ' a.attnum AS ORDINAL_POSITION, a.attname AS COLUMN_NAME,'
3229 + ' NULL AS ASC_OR_DESC, ci.reltuples AS CARDINALITY,'
3230 + ' ci.relpages AS PAGES, NULL AS FILTER_CONDITION'
3232 + ' WHERE ct.oid=i.indrelid AND ci.oid=i.indexrelid'
3233 + ' AND a.attrelid=ci.oid AND ci.relam=am.oid' + Where
3234 + ' AND ct.relname = ' + EscapeString(Table);
3237 SQL := SQL + ' AND i.indisunique';
3238 SQL := SQL + ' ORDER BY NON_UNIQUE, TYPE, INDEX_NAME, ORDINAL_POSITION';
3240 Result := CopyToVirtualResultSet(
3241 GetConnection.CreateStatement.ExecuteQuery(SQL),
3242 ConstructVirtualResultSet(IndexInfoColumnsDynArray));
3245 function TZPostgreSQLDatabaseMetadata.UncachedGetSequences(const Catalog, SchemaPattern,
3246 SequenceNamePattern: string): IZResultSet;
3250 Result:=inherited UncachedGetSequences(Catalog, SchemaPattern, SequenceNamePattern);
3252 SQL := ' SELECT nspname, relname ' +
3253 'FROM pg_catalog.pg_namespace n, pg_catalog.pg_class ct ' +
3254 'WHERE relkind = ''S'' ' +
3255 'AND n.oid = ct.relnamespace';
3257 if SequenceNamePattern <> '' then
3258 SQL := SQL + ' AND ' + Format('relname = ''%s''', [SequenceNamePattern]);
3259 if SchemaPattern <> '' then
3260 SQL := SQL + ' AND ' + Format('nspname = ''%s''', [SchemaPattern]);
3262 with GetConnection.CreateStatement.ExecuteQuery(SQL) do
3266 Result.MoveToInsertRow;
3267 Result.UpdateNull(1);
3268 Result.UpdateString(2, GetStringByName('nspname'));
3269 Result.UpdateString(3, GetStringByName('relname'));
3276 function TZPostgreSQLDatabaseMetadata.GetPostgreSQLType(Oid: Integer): string;
3278 Result := (GetConnection as IZPostgreSQLConnection).GetTypeNameByOid(Oid);
3281 function TZPostgreSQLDatabaseMetadata.GetSQLTypeByOid(Oid: Integer): TZSQLType;
3283 PostgreSQLConnection: IZPostgreSQLConnection;
3285 PostgreSQLConnection := GetConnection as IZPostgreSQLConnection;
3286 Result := PostgreSQLToSQLType(PostgreSQLConnection,
3287 PostgreSQLConnection.GetTypeNameByOid(Oid));
3290 function TZPostgreSQLDatabaseMetadata.GetSQLTypeByName(
3291 TypeName: string): TZSQLType;
3293 Result := PostgreSQLToSQLType(
3294 GetConnection as IZPostgreSQLConnection, TypeName);
3297 function TZPostgreSQLDatabaseMetadata.TableTypeSQLExpression(
3298 TableType: string; UseSchemas: Boolean): string;
3302 if TableType = 'TABLE' then
3303 Result := ' c.relkind = ''r'' AND n.nspname NOT LIKE ''pg\\_%'' '
3304 else if TableType = 'VIEW' then
3305 Result := ' c.relkind = ''v'' AND n.nspname <> ''pg_catalog'' '
3306 else if TableType = 'INDEX' then
3307 Result := ' c.relkind = ''i'' AND n.nspname NOT LIKE ''pg\\_%'' '
3308 else if TableType = 'SEQUENCE' then
3309 Result := ' c.relkind = ''S'' '
3310 else if TableType = 'SYSTEM TABLE' then
3311 Result := ' c.relkind = ''r'' AND n.nspname = ''pg_catalog'' '
3312 else if TableType = 'SYSTEM TOAST TABLE' then
3313 Result := ' c.relkind = ''r'' AND n.nspname = ''pg_toast'' '
3314 else if TableType = 'SYSTEM TOAST INDEX' then
3315 Result := ' c.relkind = ''i'' AND n.nspname = ''pg_toast'' '
3316 else if TableType = 'SYSTEM VIEW' then
3317 Result := ' c.relkind = ''v'' AND n.nspname = ''pg_catalog'' '
3318 else if TableType = 'SYSTEM INDEX' then
3319 Result := ' c.relkind = ''i'' AND n.nspname = ''pg_catalog'' '
3320 else if TableType = 'TEMPORARY TABLE' then
3321 Result := ' c.relkind = ''r'' AND n.nspname LIKE ''pg\\_temp\\_%'' '
3322 else if TableType = 'TEMPORARY INDEX' then
3323 Result := 'c.relkind = ''i'' AND n.nspname LIKE ''pg\\_temp\\_%'' ';
3327 if TableType = 'TABLE' then
3328 Result := ' c.relkind = ''r'' AND c.relname NOT LIKE ''pg\\_%'' '
3329 else if TableType = 'VIEW' then
3330 Result := ' c.relkind = ''v'' AND c.relname NOT LIKE ''pg\\_%'' '
3331 else if TableType = 'INDEX' then
3332 Result := ' c.relkind = ''i'' AND c.relname NOT LIKE ''pg\\_%'' '
3333 else if TableType = 'SEQUENCE' then
3334 Result := ' c.relkind = ''S'' '
3335 else if TableType = 'SYSTEM TABLE' then
3336 Result := ' c.relkind = ''r'' AND c.relname LIKE ''pg\\_%'' AND c.relname '+
3337 'NOT LIKE ''pg\\_toast\\_%'' AND c.relname NOT LIKE ''pg\\_temp\\_%'' '
3338 else if TableType = 'SYSTEM TOAST TABLE' then
3339 Result := ' c.relkind = ''r'' AND c.relname LIKE ''pg\\_toast\\_%'' '
3340 else if TableType = 'SYSTEM TOAST INDEX' then
3341 Result := ' c.relkind = ''i'' AND c.relname LIKE ''pg\\_toast\\_%'' '
3342 else if TableType = 'SYSTEM VIEW' then
3343 Result := 'c.relkind = ''v'' AND c.relname LIKE ''pg\\_%'''
3344 else if TableType = 'SYSTEM INDEX' then
3346 Result := ' c.relkind = ''v'' AND c.relname LIKE ''pg\\_%'' AND '+
3347 'c.relname NOT LIKE ''pg\\_toast\\_%'' AND c.relname '+
3348 'NOT LIKE ''pg\\_temp\\_%'' '
3350 else if TableType = 'TEMPORARY TABLE' then
3351 Result := ' c.relkind = ''r'' AND c.relname LIKE ''pg\\_temp\\_%'' '
3352 else if TableType = 'TEMPORARY INDEX' then
3353 Result := ' c.relkind = ''i'' AND c.relname LIKE ''pg\\_temp\\_%'' '
3357 procedure TZPostgreSQLDatabaseMetadata.ParseACLArray(
3358 List: TStrings; AclString: string);
3362 I, BeginIndex: Integer;
3364 if AclString = '' then Exit;
3368 for I := BeginIndex to Length(AclString) do
3370 if (AclString[I] = '"') and (PrevChar <> '\' ) then
3371 InQuotes := not InQuotes
3372 else if (AclString[I] = ',') and not InQuotes then
3374 List.Add(Copy(AclString, BeginIndex, I - BeginIndex));
3377 PrevChar := AclString[I];
3380 // add last element removing the trailing "}"
3381 List.Add(Copy(AclString, BeginIndex, Length(AclString) - BeginIndex));
3383 // Strip out enclosing quotes, if any.
3384 for I := 0 to List.Count-1 do
3386 if (List.Strings[i][1] = '"')
3387 and (List.Strings[i][Length(List.Strings[i])] = '"') then
3388 List.Strings[i] := Copy(List.Strings[i], 2, Length(List.Strings[i])-2);
3392 function TZPostgreSQLDatabaseMetadata.GetPrivilegeName(Permission: Char): string;
3395 'a': Result := 'INSERT';
3396 'r': Result := 'SELECT';
3397 'w': Result := 'UPDATE';
3398 'd': Result := 'DELETE';
3399 'R': Result := 'RULE';
3400 'x': Result := 'REFERENCES';
3401 't': Result := 'TRIGGER';
3402 'X': Result := 'EXECUTE';
3403 'U': Result := 'USAGE';
3404 'C': Result := 'CREATE';
3405 'T': Result := 'CREATE TEMP';
3406 else Result := 'UNKNOWN';
3410 function TZPostgreSQLDatabaseMetadata.GetIdentifierConvertor: IZIdentifierConvertor;
3412 Result:=TZPostgreSQLIdentifierConvertor.Create(Self);
3416 Gets the all supported CharacterSets:
3417 @return <code>ResultSet</code> - each row is a CharacterSetName and it's ID
3419 function TZPostgreSQLDatabaseMetadata.UncachedGetCharacterSets: IZResultSet; //EgonHugeist
3421 Self.GetConnection.CreateStatement.Execute(
3422 ' CREATE OR REPLACE FUNCTION get_encodings() RETURNS INTEGER AS '''+
3424 ' enc INTEGER := 0; '+
3427 ' CREATE TEMP TABLE encodings ( enc_code int, enc_name text ); '+
3429 ' SELECT INTO name pg_encoding_to_char( enc ); '+
3430 ' IF( name = '''''''' ) THEN '+
3433 ' INSERT INTO encodings VALUES( enc, name ); '+
3435 ' enc := enc + 1; '+
3439 ''' LANGUAGE ''plpgsql'';');
3440 Self.GetConnection.CreateStatement.ExecuteQuery('select get_encodings();').Close;
3442 Result:=inherited UncachedGetCharacterSets;
3444 with Self.GetConnection.CreateStatement.ExecuteQuery(
3445 'select * from encodings;') do
3449 Result.MoveToInsertRow;
3450 Result.UpdateString(1, GetString(2)); //CHARACTER_SET_NAME
3451 Result.UpdateShort(2, GetShort(1)); //CHARACTER_SET_ID
3458 { TZPostgresIdentifierConvertor }
3460 function TZPostgreSQLIdentifierConvertor.ExtractQuote(
3461 const Value: string): string;
3465 QuoteDelim := Metadata.GetDatabaseInfo.GetIdentifierQuoteString;
3467 if (QuoteDelim <> '') and (Value <> '') then
3468 if (Value[1]=QuoteDelim[1]) and
3469 (Value[PLongInt(NativeUInt(Value) - 4)^{fast Length()}]=QuoteDelim[1]) then
3471 Result:=copy(Value,2,length(Value)-2);
3472 Result:=StringReplace(Result,QuoteDelim+QuoteDelim,QuoteDelim,[rfReplaceAll]);
3475 Result := AnsiLowerCase(Value);
3479 function TZPostgreSQLIdentifierConvertor.IsQuoted(const Value: string): Boolean;
3483 QuoteDelim := Metadata.GetDatabaseInfo.GetIdentifierQuoteString;
3484 Result := (QuoteDelim <> '') and (Value <> '') and
3485 (Value[1]=QuoteDelim[1]) and
3486 (Value[PLongInt(NativeUInt(Value) - 4)^{fast Length()}]=QuoteDelim[1]);
3489 function TZPostgreSQLIdentifierConvertor.IsSpecialCase(
3490 const Value: string): Boolean;
3495 if not CharInSet(Value[1], ['a'..'z','_']) then
3500 for I := 1 to Length(Value) do
3502 if not CharInSet(Value[I], ['A'..'Z','a'..'z','0'..'9','_']) then
3510 function TZPostgreSQLIdentifierConvertor.Quote(const Value: string): string;
3515 if IsCaseSensitive(Value) then
3517 QuoteDelim := Metadata.GetDatabaseInfo.GetIdentifierQuoteString;
3518 Result := QuoteDelim +
3519 StringReplace(Result,QuoteDelim,QuoteDelim+QuoteDelim,[rfReplaceAll]) +