ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/IBExtract.pas
Revision: 225
Committed: Tue Apr 3 09:09:05 2018 UTC (6 years ago) by tony
Content type: text/x-pascal
File size: 130975 byte(s)
Log Message:
Fixes Merged

File Contents

# Content
1 {************************************************************************}
2 { }
3 { The contents of this file are subject to the InterBase }
4 { Public License Version 1.0 (the "License"); you may not }
5 { use this file except in compliance with the License. You }
6 { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
7 { Software distributed under the License is distributed on }
8 { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
9 { express or implied. See the License for the specific language }
10 { governing rights and limitations under the License. }
11 { }
12 { The Original Code was created by Jeff Overcash. }
13 { Portions based upon code by Inprise Corporation are Copyright (C) }
14 { Inprise Corporation. All Rights Reserved. }
15 { }
16 { IBX Version 4.2 or higher required }
17 { Contributor(s): Jeff Overcash }
18 { }
19 { IBX For Lazarus (Firebird Express) }
20 { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
21 { Portions created by MWA Software are copyright McCallum Whyman }
22 { Associates Ltd 2011 - 2018 }
23 { }
24 {************************************************************************}
25
26 { Syntax Enhancements Supported (by Firebird Version no.):
27
28 Multi-action triggers (1.5)
29 CREATE SEQUENCE (2.0)
30 Database Triggers (2.1)
31 Global Temporary Tables (2.1)
32 Boolean Type (3.0)
33 Identity Column Type (3.0)
34 DDL Triggers (3.0)
35 }
36
37 unit IBExtract;
38
39 {$Mode Delphi}
40 {$codepage UTF8}
41
42 interface
43
44 uses
45 {$IFDEF WINDOWS }
46 Windows,
47 {$ELSE}
48 unix,
49 {$ENDIF}
50 SysUtils, Classes, IBDatabase, IBDatabaseInfo,
51 IBSQL, IBUtils, IBHeader, IB;
52
53 type
54 TExtractObjectTypes =
55 (eoDatabase, eoDomain, eoTable, eoView, eoProcedure, eoFunction, eoPackage,
56 eoGenerator, eoException, eoBLOBFilter, eoRole, eoTrigger, eoForeign,
57 eoIndexes, eoChecks, eoData);
58
59 TExtractType =
60 (etDomain, etTable, etRole, etTrigger, etForeign,
61 etIndex, etData, etGrant, etCheck, etGrantsToUser);
62
63 TExtractTypes = Set of TExtractType;
64
65 TProcDDLType = (pdCreateProc,pdCreateStub,pdAlterProc);
66
67 TPackageDDLType = (paHeader,paBody,paBoth);
68
69 { TIBExtract }
70
71 TIBExtract = class(TComponent)
72 private
73 FAlwaysQuoteIdentifiers: boolean;
74 FCaseSensitiveObjectNames: boolean;
75 FDatabase : TIBDatabase;
76 FTransaction : TIBTransaction;
77 FMetaData: TStrings;
78 FDatabaseInfo: TIBDatabaseInfo;
79 FShowSystem: Boolean;
80 { Private declarations }
81 procedure Add2MetaData(const Msg: string; IsError: boolean=true);
82 function GetDatabase: TIBDatabase;
83 function GetIndexSegments ( indexname : String) : String;
84 function GetTransaction: TIBTransaction;
85 function GetTriggerType(TypeID: Int64): string;
86 procedure SetDatabase(const Value: TIBDatabase);
87 procedure SetTransaction(const Value: TIBTransaction);
88 function PrintValidation(ToValidate : String; flag : Boolean) : String;
89 procedure ShowGrants(MetaObject: String; Terminator : String; NoUserGrants: boolean=false);
90 procedure ShowGrantsTo(MetaObject: String; ObjectType: integer;
91 Terminator: String);
92 procedure ShowGrantRoles(Terminator : String);
93 procedure GetProcedureArgs(Proc : String);
94 protected
95 function ExtractDDL(Flag: Boolean; TableName: String; ExtractTypes: TExtractTypes =
96 []): Boolean;
97 function ExtractListTable(RelationName, NewName: String; DomainFlag: Boolean): Boolean;
98 procedure ExtractListView (ViewName : String);
99 procedure ListData(ObjectName : String);
100 procedure ListRoles(ObjectName : String = ''; IncludeGrants:boolean=false);
101 procedure ListGrants(ExtractTypes : TExtractTypes = []);
102 procedure ListPackages(PackageDDLType: TPackageDDLType; PackageName: string = ''; IncludeGrants:boolean = false);
103 procedure ListProcs(ProcDDLType: TProcDDLType = pdCreateProc; ProcedureName : String = '';
104 IncludeGrants:boolean=false);
105 procedure ListAllTables(flag : Boolean);
106 procedure ListTriggers(ObjectName: String=''; ExtractTypes: TExtractTypes = [etTrigger]);
107 procedure ListCheck(ObjectName : String = ''; ExtractType : TExtractType = etCheck);
108 function PrintSet(var Used : Boolean) : String;
109 procedure ListCreateDb(TargetDb : String = '');
110 procedure ListDomains(ObjectName : String = ''; ExtractType : TExtractType = etDomain);
111 procedure ListException(ExceptionName : String = '');
112 procedure ListFilters(FilterName : String = '');
113 procedure ListForeign(ObjectName : String = ''; ExtractType : TExtractType = etForeign);
114 procedure ListFunctions(FunctionName : String = '');
115 procedure ListGenerators(GeneratorName : String = ''; ExtractTypes: TExtractTypes=[]);
116 procedure ListIndex(ObjectName : String = ''; ExtractType : TExtractType = etIndex);
117 procedure ListViews(ViewName : String = '');
118 procedure Notification(AComponent: TComponent; Operation: TOperation); override;
119 function QuoteIdentifier(Value: String): String;
120
121 { Protected declarations }
122 public
123 { Public declarations }
124 constructor Create(AOwner : TComponent); override;
125 destructor Destroy; override;
126 function GetArrayField(FieldName : String) : String;
127 function GetFieldType(FieldType, FieldSubType, FieldScale, FieldSize,
128 FieldPrec, FieldLen : Integer) : String;
129 function GetCharacterSets(CharSetId, Collation : integer; CollateOnly : Boolean) : String;
130 procedure ExtractObject(ObjectType : TExtractObjectTypes; ObjectName : String = '';
131 ExtractTypes : TExtractTypes = []);
132 property DatabaseInfo : TIBDatabaseInfo read FDatabaseInfo;
133 property Items : TStrings read FMetaData;
134
135 published
136 { Published declarations }
137 property Database : TIBDatabase read GetDatabase write SetDatabase;
138 property Transaction : TIBTransaction read GetTransaction write SetTransaction;
139 property ShowSystem: Boolean read FShowSystem write FShowSystem;
140 property AlwaysQuoteIdentifiers: boolean read FAlwaysQuoteIdentifiers write FAlwaysQuoteIdentifiers;
141 property CaseSensitiveObjectNames: boolean read FCaseSensitiveObjectNames write FCaseSensitiveObjectNames;
142 end;
143
144 TSQLType = record
145 SqlType : Integer;
146 TypeName : String;
147 end;
148
149 TPrivTypes = record
150 PrivFlag : Integer;
151 PrivString : String;
152 end;
153
154 TSQLTypes = Array[0..14] of TSQLType;
155
156 const
157
158 priv_UNKNOWN = 1;
159 priv_SELECT = 2;
160 priv_INSERT = 4;
161 priv_UPDATE = 8;
162 priv_DELETE = 16;
163 priv_EXECUTE = 32;
164 priv_REFERENCES = 64;
165 priv_USAGE = 128;
166
167 PrivTypes : Array[0..6] of TPrivTypes = (
168 (PrivFlag : priv_DELETE; PrivString : 'DELETE' ),
169 (PrivFlag : priv_EXECUTE; PrivString : 'EXECUTE' ),
170 (PrivFlag : priv_INSERT; PrivString : 'INSERT' ),
171 (PrivFlag : priv_SELECT; PrivString : 'SELECT' ),
172 (PrivFlag : priv_UPDATE; PrivString : 'UPDATE' ),
173 (PrivFlag : priv_REFERENCES; PrivString : 'REFERENCES'),
174 (PrivFlag : priv_USAGE; PrivString : 'USAGE' ));
175
176 ColumnTypes : TSQLTypes = (
177 (SqlType : blr_short; TypeName : 'SMALLINT'), { NTX: keyword }
178 (SqlType : blr_long; TypeName : 'INTEGER'), { NTX: keyword }
179 (SqlType : blr_quad; TypeName : 'QUAD'), { NTX: keyword }
180 (SqlType : blr_float; TypeName : 'FLOAT'), { NTX: keyword }
181 (SqlType : blr_text; TypeName : 'CHAR'), { NTX: keyword }
182 (SqlType : blr_double; TypeName : 'DOUBLE PRECISION'), { NTX: keyword }
183 (SqlType : blr_varying; TypeName : 'VARCHAR'), { NTX: keyword }
184 (SqlType : blr_cstring; TypeName : 'CSTRING'), { NTX: keyword }
185 (SqlType : blr_blob_id; TypeName : 'BLOB_ID'), { NTX: keyword }
186 (SqlType : blr_blob; TypeName : 'BLOB'), { NTX: keyword }
187 (SqlType : blr_sql_time; TypeName : 'TIME'), { NTX: keyword }
188 (SqlType : blr_sql_date; TypeName : 'DATE'), { NTX: keyword }
189 (SqlType : blr_timestamp; TypeName : 'TIMESTAMP'), { NTX: keyword }
190 (SqlType : blr_int64; TypeName : 'INT64'),
191 (SqlType : blr_bool; TypeName : 'BOOLEAN'));
192
193 SubTypes : Array[0..8] of String = (
194 'UNKNOWN', { NTX: keyword }
195 'TEXT', { NTX: keyword }
196 'BLR', { NTX: keyword }
197 'ACL', { NTX: keyword }
198 'RANGES', { NTX: keyword }
199 'SUMMARY', { NTX: keyword }
200 'FORMAT', { NTX: keyword }
201 'TRANSACTION_DESCRIPTION', { NTX: keyword }
202 'EXTERNAL_FILE_DESCRIPTION'); { NTX: keyword }
203
204 IntegralSubtypes : Array[0..2] of String = (
205 'UNKNOWN', { Defined type, NTX: keyword }
206 'NUMERIC', { NUMERIC, NTX: keyword }
207 'DECIMAL'); { DECIMAL, NTX: keyword }
208
209 ODS_VERSION6 = 6; { on-disk structure as of v3.0 }
210 ODS_VERSION7 = 7; { new on disk structure for fixing index bug }
211 ODS_VERSION8 = 8; { new btree structure to support pc semantics }
212 ODS_VERSION9 = 9; { btree leaf pages are always propogated up }
213 ODS_VERSION10 = 10; { V6.0 features. SQL delimited idetifier,
214 SQLDATE, and 64-bit exact numeric
215 type }
216 ODS_VERSION12 = 12; {Firebird 3}
217
218 { flags for RDB$FILE_FLAGS }
219 FILE_shadow = 1;
220 FILE_inactive = 2;
221 FILE_manual = 4;
222 FILE_cache = 8;
223 FILE_conditional = 16;
224
225 { flags for RDB$LOG_FILES }
226 LOG_serial = 1;
227 LOG_default = 2;
228 LOG_raw = 4;
229 LOG_overflow = 8;
230
231
232
233 MAX_INTSUBTYPES = 2;
234 MAXSUBTYPES = 8; { Top of subtypes array }
235
236 { Object types used in RDB$DEPENDENCIES and RDB$USER_PRIVILEGES }
237
238 obj_relation = 0;
239 obj_view = 1;
240 obj_trigger = 2;
241 obj_computed = 3;
242 obj_validation = 4;
243 obj_procedure = 5;
244 obj_expression_index = 6;
245 obj_exception = 7;
246 obj_user = 8;
247 obj_field = 9;
248 obj_index = 10;
249 obj_count = 11;
250 obj_user_group = 12;
251 obj_sql_role = 13;
252 obj_package = 18;
253
254 implementation
255
256 uses FBMessages, IBDataOutput;
257
258 const
259 TERM = ';';
260 ProcTerm = '^';
261
262 CollationSQL =
263 'SELECT CST.RDB$CHARACTER_SET_NAME, COL.RDB$COLLATION_NAME, CST.RDB$DEFAULT_COLLATE_NAME ' +
264 'FROM RDB$COLLATIONS COL JOIN RDB$CHARACTER_SETS CST ON ' +
265 ' COL.RDB$CHARACTER_SET_ID = CST.RDB$CHARACTER_SET_ID ' +
266 'WHERE ' +
267 ' COL.RDB$COLLATION_ID = :COLLATION AND ' +
268 ' CST.RDB$CHARACTER_SET_ID = :CHAR_SET_ID ' +
269 'ORDER BY COL.RDB$COLLATION_NAME, CST.RDB$CHARACTER_SET_NAME';
270
271 NonCollationSQL =
272 'SELECT CST.RDB$CHARACTER_SET_NAME ' +
273 'FROM RDB$CHARACTER_SETS CST ' +
274 'WHERE CST.RDB$CHARACTER_SET_ID = :CHARSETID ' +
275 'ORDER BY CST.RDB$CHARACTER_SET_NAME';
276
277 PrecisionSQL =
278 'SELECT * FROM RDB$FIELDS ' +
279 'WHERE RDB$FIELD_NAME = :FIELDNAME';
280
281 ArraySQL =
282 'SELECT * FROM RDB$FIELD_DIMENSIONS FDIM ' +
283 'WHERE ' +
284 ' FDIM.RDB$FIELD_NAME = :FIELDNAME ' +
285 'ORDER BY FDIM.RDB$DIMENSION';
286
287 type
288 TTriggerPhase = (tpNone,tpCreate,tpAlter,tpDrop);
289
290 TDDLTriggerMap = record
291 ObjectName: string;
292 Bits: integer;
293 Bit1: TTriggerPhase;
294 Bit2: TTriggerPhase;
295 Bit3: TTriggerPhase;
296 end;
297
298 const
299 DDLTriggers : array [0..15] of TDDLTriggerMap = (
300 (ObjectName: 'TABLE'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
301 (ObjectName: 'PROCEDURE'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
302 (ObjectName: 'FUNCTION'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
303 (ObjectName: 'TRIGGER'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
304 (ObjectName: 'Empty slot'; Bits: 3; Bit1: tpNone; Bit2: tpNone; Bit3: tpNone),
305 (ObjectName: 'EXCEPTION'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
306 (ObjectName: 'VIEW'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
307 (ObjectName: 'DOMAIN'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
308 (ObjectName: 'ROLE'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
309 (ObjectName: 'INDEX'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
310 (ObjectName: 'SEQUENCE'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
311 (ObjectName: 'USER'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
312 (ObjectName: 'COLLATION'; Bits: 2; Bit1: tpCreate; Bit2: tpDrop; Bit3: tpNone),
313 (ObjectName: 'CHARACTER SET'; Bits: 1; Bit1: tpAlter; Bit2: tpNone; Bit3: tpNone),
314 (ObjectName: 'PACKAGE'; Bits: 3; Bit1: tpCreate; Bit2: tpAlter; Bit3: tpDrop),
315 (ObjectName: 'PACKAGE BODY'; Bits: 2; Bit1: tpCreate; Bit2: tpDrop; Bit3: tpNone)
316 );
317
318 { TIBExtract }
319
320 { ArrayDimensions
321 Functional description
322 Retrieves the dimensions of arrays and prints them.
323
324 Parameters: fieldname -- the actual name of the array field }
325
326 function TIBExtract.GetArrayField(FieldName: String): String;
327 var
328 qryArray : TIBSQL;
329 begin
330 qryArray := TIBSQL.Create(FDatabase);
331 Result := '';
332 qryArray.SQL.Add(ArraySQL);
333 qryArray.Params.ByName('FieldName').AsString := FieldName;
334 qryArray.ExecQuery;
335
336 { Format is [lower:upper, lower:upper,..] }
337
338 if not qryArray.Eof then
339 begin
340 Result := '[';
341 while not qryArray.Eof do
342 begin
343 if (qryArray.FieldByName('RDB$DIMENSION').AsInteger > 0) then
344 Result := Result + ', ';
345 Result := Result + qryArray.FieldByName('RDB$LOWER_BOUND').AsString + ':' +
346 qryArray.FieldByName('RDB$UPPER_BOUND').AsString;
347 qryArray.Next;
348 end;
349 Result := Result + '] ';
350 end;
351
352 qryArray.Free;
353
354 end;
355
356 constructor TIBExtract.Create(AOwner: TComponent);
357 begin
358 inherited;
359 FMetaData := TStringList.Create;
360 FDatabaseInfo := TIBDatabaseInfo.Create(nil);
361 FDatabaseInfo.Database := FDatabase;
362 if AOwner is TIBDatabase then
363 Database := TIBDatabase(AOwner);
364 if AOwner is TIBTransaction then
365 Transaction := TIBTransaction(AOwner);
366 end;
367
368 destructor TIBExtract.Destroy;
369 begin
370 FMetaData.Free;
371 FDatabasEInfo.Free;
372 inherited;
373 end;
374
375 function TIBExtract.ExtractDDL(Flag: Boolean; TableName: String;
376 ExtractTypes: TExtractTypes): Boolean;
377 var
378 DidConnect : Boolean;
379 DidStart : Boolean;
380 begin
381 Result := true;
382 DidConnect := false;
383 DidStart := false;
384
385 if not FDatabase.Connected then
386 begin
387 FDatabase.Connected := true;
388 didConnect := true;
389 end;
390
391 FMetaData.Add(Format('SET SQL DIALECT %d;', [FDatabase.SQLDialect]));
392 FMetaData.Add('SET AUTODDL ON;');
393 FMetaData.Add('');
394
395 if not FTransaction.Active then
396 begin
397 FTransaction.StartTransaction;
398 DidStart := true;
399 end;
400
401 if TableName <> '' then
402 begin
403 if not ExtractListTable(TableName, '', true) then
404 Result := false;
405 end
406 else
407 begin
408 ListCreateDb;
409 ListFilters;
410 ListFunctions;
411 ListDomains;
412 ListAllTables(flag);
413 if etData in ExtractTypes then
414 ListData('');
415 ListIndex;
416 ListForeign;
417 if etData in ExtractTypes then
418 ListGenerators('',[etData])
419 else
420 ListGenerators;
421 ListViews;
422 ListCheck;
423 ListException;
424 if DatabaseInfo.ODSMajorVersion >= ODS_VERSION12 then
425 ListPackages(paHeader);
426 ListProcs(pdCreateStub);
427 ListTriggers;
428 if DatabaseInfo.ODSMajorVersion >= ODS_VERSION12 then
429 ListPackages(paBody);
430 ListProcs(pdAlterProc);
431 ListGrants(ExtractTypes);
432 end;
433
434 if DidStart then
435 FTransaction.Commit;
436
437 if DidConnect then
438 FDatabase.Connected := false;
439 end;
440
441 { ExtractListTable
442 Functional description
443 Shows columns, types, info for a given table name
444 and text of views.
445 If a new_name is passed, substitute it for relation_name
446
447 relation_name -- Name of table to investigate
448 new_name -- Name of a new name for a replacement table
449 domain_flag -- extract needed domains before the table }
450
451 function TIBExtract.ExtractListTable(RelationName, NewName: String;
452 DomainFlag: Boolean): Boolean;
453 const
454 TableListSQL =
455 'SELECT * FROM RDB$RELATIONS REL JOIN RDB$RELATION_FIELDS RFR ON ' + {Do Not Localize}
456 ' RFR.RDB$RELATION_NAME = REL.RDB$RELATION_NAME JOIN RDB$FIELDS FLD ON ' +
457 ' RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME ' +
458 'WHERE REL.RDB$RELATION_NAME = :RelationName ' +
459 'ORDER BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME';
460
461 ConstraintSQL =
462 'SELECT RCO.RDB$CONSTRAINT_NAME, RDB$CONSTRAINT_TYPE, RDB$RELATION_NAME, ' +
463 'RDB$DEFERRABLE, RDB$INITIALLY_DEFERRED, RDB$INDEX_NAME, RDB$TRIGGER_NAME ' +
464 'FROM RDB$RELATION_CONSTRAINTS RCO, RDB$CHECK_CONSTRAINTS CON ' +
465 'WHERE ' +
466 ' CON.RDB$TRIGGER_NAME = :FIELDNAME AND ' +
467 ' CON.RDB$CONSTRAINT_NAME = RCO.RDB$CONSTRAINT_NAME AND ' +
468 ' RCO.RDB$CONSTRAINT_TYPE = ''NOT NULL'' AND ' +
469 ' RCO.RDB$RELATION_NAME = :RELATIONNAME';
470
471 RelConstraintsSQL =
472 'SELECT * FROM RDB$RELATION_CONSTRAINTS RELC ' +
473 'WHERE ' +
474 ' (RELC.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'' OR ' +
475 ' RELC.RDB$CONSTRAINT_TYPE = ''UNIQUE'') AND ' +
476 ' RELC.RDB$RELATION_NAME = :RELATIONNAME ' +
477 'ORDER BY RELC.RDB$CONSTRAINT_TYPE desc, RELC.RDB$CONSTRAINT_NAME';
478
479 GetGeneratorSQL =
480 'SELECT * FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = :GENERATOR';
481
482 var
483 Collation, CharSetId : integer;
484 i : integer;
485 Column, Constraint : String;
486 SubType : integer;
487 IntChar : integer;
488 qryTables, qryPrecision, qryConstraints, qryRelConstraints, qryGenerators : TIBSQL;
489 PrecisionKnown, ValidRelation : Boolean;
490 FieldScale, FieldType : Integer;
491 CreateTable: string;
492 TableType: integer;
493 begin
494 Result := true;
495 IntChar := 0;
496 ValidRelation := false;
497
498 if DomainFlag then
499 ListDomains(RelationName);
500 qryTables := TIBSQL.Create(FDatabase);
501 qryPrecision := TIBSQL.Create(FDatabase);
502 qryConstraints := TIBSQL.Create(FDatabase);
503 qryRelConstraints := TIBSQL.Create(FDatabase);
504 qryGenerators := TIBSQL.Create(FDatabase);
505 try
506 qryTables.SQL.Add(TableListSQL);
507 RelationName := trim(RelationName);
508 qryTables.Params.ByName('RelationName').AsString := RelationName;
509 qryTables.ExecQuery;
510 qryPrecision.SQL.Add(PrecisionSQL);
511 qryConstraints.SQL.Add(ConstraintSQL);
512 qryRelConstraints.SQL.Add(RelConstraintsSQL);
513 qryGenerators.SQL.Add(GetGeneratorSQL);
514 if not qryTables.Eof then
515 begin
516 ValidRelation := true;
517 TableType := qryTables.FieldByName('RDB$RELATION_TYPE').AsInteger;
518 if (not qryTables.FieldByName('RDB$OWNER_NAME').IsNull) and
519 (Trim(qryTables.FieldByName('RDB$OWNER_NAME').AsString) <> '') then
520 FMetaData.Add(Format('%s/* Table: %s, Owner: %s */%s',
521 [LineEnding, RelationName,
522 qryTables.FieldByName('RDB$OWNER_NAME').AsString, LineEnding]));
523 if TableType > 3 then
524 CreateTable := 'CREATE GLOBAL TEMPORARY TABLE'
525 else
526 CreateTable := 'CREATE TABLE';
527 if NewName <> '' then
528 FMetaData.Add(Format('%s %s ', [CreateTable,QuoteIdentifier(NewName)]))
529 else
530 FMetaData.Add(Format('%s %s ', [CreateTable,QuoteIdentifier(RelationName)]));
531 if not qryTables.FieldByName('RDB$EXTERNAL_FILE').IsNull then
532 FMetaData.Add(Format('EXTERNAL FILE %s ',
533 [QuotedStr(qryTables.FieldByName('RDB$EXTERNAL_FILE').AsString)]));
534 FMetaData.Add('(');
535 end;
536
537 while not qryTables.Eof do
538 begin
539 Column := ' ' + QuoteIdentifier( qryTables.FieldByName('RDB$FIELD_NAME').AsString) + TAB;
540
541 { Check first for computed fields, then domains.
542 If this is a known domain, then just print the domain rather than type
543 Domains won't have length, array, or blob definitions, but they
544 may have not null, default and check overriding their definitions }
545
546 if not qryTables.FieldByName('rdb$computed_blr').IsNull then
547 begin
548 Column := Column + ' COMPUTED BY ';
549 if not qryTables.FieldByName('RDB$COMPUTED_SOURCE').IsNull then
550 Column := Column + PrintValidation(qryTables.FieldByName('RDB$COMPUTED_SOURCE').AsString, true);
551 end
552 else
553 begin
554 FieldType := qryTables.FieldByName('RDB$FIELD_TYPE').AsInteger;
555 FieldScale := qryTables.FieldByName('RDB$FIELD_SCALE').AsInteger;
556 if not ((Copy(qryTables.FieldByName('RDB$FIELD_NAME1').AsString, 1, 4) = 'RDB$') and
557 (qryTables.FieldByName('RDB$FIELD_NAME1').AsString[5] in ['0'..'9'])) and
558 (qryTables.FieldByName('RDB$SYSTEM_FLAG').AsInteger <> 1) then
559 begin
560 Column := Column + QuoteIdentifier( trim(qryTables.FieldByName('RDB$FIELD_NAME1').AsString));
561 { International character sets }
562 if (qryTables.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_text, blr_varying])
563 and (not qryTables.FieldByName('RDB$COLLATION_ID').IsNull)
564 and (qryTables.FieldByName('RDB$COLLATION_ID').AsInteger <> 0) then
565 begin
566 Collation := qryTables.FieldByName('RDB$COLLATION_ID').AsInteger;
567 Column := Column + GetCharacterSets(qryTables.FieldByName('RDB$CHARACTER_SET_ID').AsShort,
568 Collation, true);
569 end;
570 end
571 else
572 begin
573 { Look through types array }
574 for i := Low(Columntypes) to High(ColumnTypes) do
575 begin
576 PrecisionKnown := false;
577 if qryTables.FieldByname('RDB$FIELD_TYPE').AsShort = ColumnTypes[i].SQLType then
578 begin
579
580 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
581 begin
582 { Handle Integral subtypes NUMERIC and DECIMAL }
583 if qryTables.FieldByName('RDB$FIELD_TYPE').AsInteger in
584 [blr_short, blr_long, blr_int64] then
585 begin
586 qryPrecision.Params.ByName('FIELDNAME').AsString :=
587 qryTables.FieldByName('RDB$FIELD_NAME1').AsString;
588 qryPrecision.ExecQuery;
589
590 { We are ODS >= 10 and could be any Dialect }
591 if not qryPrecision.FieldByName('RDB$FIELD_PRECISION').IsNull then
592 begin
593 { We are Dialect >=3 since FIELD_PRECISION is non-NULL }
594 if (qryPrecision.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger > 0) and
595 (qryPrecision.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger <= MAX_INTSUBTYPES) then
596 begin
597 Column := column + Format('%s(%d, %d)',
598 [IntegralSubtypes[qryPrecision.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger],
599 qryPrecision.FieldByName('RDB$FIELD_PRECISION').AsInteger,
600 -qryPrecision.FieldByName('RDB$FIELD_SCALE').AsInteger]);
601 PrecisionKnown := TRUE;
602 end;
603 end;
604 qryPrecision.Close;
605 end;
606 end;
607
608 if PrecisionKnown = FALSE then
609 begin
610 { Take a stab at numerics and decimals }
611 if (FieldType = blr_short) and (FieldScale < 0) then
612 Column := Column + Format('NUMERIC(4, %d)', [-FieldScale])
613 else
614 if (FieldType = blr_long) and (FieldScale < 0) then
615 Column := Column + Format('NUMERIC(9, %d)', [-FieldScale])
616 else
617 if (FieldType = blr_double) and (FieldScale < 0) then
618 Column := Column + Format('NUMERIC(15, %d)', [-FieldScale])
619 else
620 Column := Column + ColumnTypes[i].TypeName;
621 end;
622 end;
623 end;
624 if FieldType in [blr_text, blr_varying] then
625 if qryTables.FieldByName('RDB$CHARACTER_LENGTH').IsNull then
626 Column := Column + Format('(%d)', [qryTables.FieldByName('RDB$FIELD_LENGTH').AsInteger])
627 else
628 Column := Column + Format('(%d)', [qryTables.FieldByName('RDB$CHARACTER_LENGTH').AsInteger]);
629
630 { Catch arrays after printing the type }
631
632 if not qryTables.FieldByName('RDB$DIMENSIONS').IsNull and (qryTables.FieldByName('RDB$DIMENSIONS').AsInteger > 0) then
633 Column := column + GetArrayField(qryTables.FieldByName('RDB$FIELD_SOURCE').AsString);
634
635 if FieldType = blr_blob then
636 begin
637 subtype := qryTables.FieldByName('RDB$FIELD_SUB_TYPE').AsShort;
638 Column := Column + ' SUB_TYPE ';
639 if (subtype > 0) and (subtype <= MAXSUBTYPES) then
640 Column := Column + SubTypes[subtype]
641 else
642 Column := Column + IntToStr(subtype);
643 column := Column + Format(' SEGMENT SIZE %d',
644 [qryTables.FieldByName('RDB$SEGMENT_LENGTH').AsInteger]);
645 end;
646
647 { International character sets }
648 if ((FieldType in [blr_text, blr_varying]) or
649 (FieldType = blr_blob)) and
650 (not qryTables.FieldByName('RDB$CHARACTER_SET_ID').IsNull) and
651 (qryTables.FieldByName('RDB$CHARACTER_SET_ID').AsInteger <> 0) then
652 begin
653 { Override rdb$fields id with relation_fields if present }
654
655 CharSetId := 0;
656 if not qryTables.FieldByName('RDB$CHARACTER_SET_ID').IsNull then
657 CharSetId := qryTables.FieldByName('RDB$CHARACTER_SET_ID').AsInteger;
658
659 Column := Column + GetCharacterSets(CharSetId, 0, false);
660 intchar := 1;
661 end;
662 end;
663
664 {Firebird 3 introduces IDENTITY columns. We need to check for them here}
665 if qryTables.HasField('RDB$GENERATOR_NAME') and not qryTables.FieldByName('RDB$GENERATOR_NAME').IsNull then
666 begin
667 qryGenerators.ParamByName('GENERATOR').AsString := qryTables.FieldByName('RDB$GENERATOR_NAME').AsString;
668 qryGenerators.ExecQuery;
669 if not qryGenerators.Eof then
670 begin
671 Column := Column + Format(' GENERATED BY DEFAULT AS IDENTITY (START WITH %d)',
672 [qryGenerators.FieldByName('RDB$INITIAL_VALUE').AsInt64]);
673 end;
674 qryGenerators.Close;
675 end;
676
677 { Handle defaults for columns }
678 { Originally This called PrintMetadataTextBlob,
679 should no longer need }
680 if not qryTables.FieldByName('RDB$DEFAULT_SOURCE').IsNull then
681 Column := Column + ' ' + qryTables.FieldByName('RDB$DEFAULT_SOURCE').AsString;
682
683
684 { The null flag is either 1 or null (for nullable) . if there is
685 a constraint name, print that too. Domains cannot have named
686 constraints. The column name is in rdb$trigger_name in
687 rdb$check_constraints. We hope we get at most one row back. }
688
689 if qryTables.FieldByName('RDB$NULL_FLAG').AsInteger = 1 then
690 begin
691 qryConstraints.Params.ByName('FIELDNAME').AsString := qryTables.FieldByName('RDB$FIELD_NAME').AsString;
692 qryConstraints.Params.ByName('RELATIONNAME').AsString := qryTables.FieldByName('RDB$RELATION_NAME').AsString;
693 qryConstraints.ExecQuery;
694
695 while not qryConstraints.Eof do
696 begin
697 if Pos('INTEG', qryConstraints.FieldByName('RDB$CONSTRAINT_NAME').AsString) <> 1 then
698 Column := Column + Format(' CONSTRAINT %s',
699 [ QuoteIdentifier(
700 qryConstraints.FieldByName('RDB$CONSTRAINT_NAME').AsString)]);
701 qryConstraints.Next;
702 end;
703 qryConstraints.Close;
704 Column := Column + ' NOT NULL';
705 end;
706
707 if ((FieldType in [blr_text, blr_varying]) or
708 (FieldType = blr_blob)) and
709 (not qryTables.FieldByName('RDB$CHARACTER_SET_ID').IsNull) and
710 (qryTables.FieldByName('RDB$CHARACTER_SET_ID').AsInteger <> 0) and
711 (intchar <> 0) then
712 begin
713 Collation := 0;
714 if not qryTables.FieldByName('RDB$COLLATION_ID1').IsNull then
715 Collation := qryTables.FieldByName('RDB$COLLATION_ID1').AsInteger
716 else
717 if not qryTables.FieldByName('RDB$COLLATION_ID').IsNull then
718 Collation := qryTables.FieldByName('RDB$COLLATION_ID').AsInteger;
719
720 CharSetId := 0;
721 if not qryTables.FieldByName('RDB$CHARACTER_SET_ID').IsNull then
722 CharSetId := qryTables.FieldByName('RDB$CHARACTER_SET_ID').AsInteger;
723
724 if Collation <> 0 then
725 Column := Column + GetCharacterSets(CharSetId, Collation, true);
726 end;
727 end;
728 qryTables.Next;
729 if not qryTables.Eof then
730 Column := Column + ',';
731 FMetaData.Add(Column);
732 end;
733
734 { Do primary and unique keys only. references come later }
735
736 qryRelConstraints.Params.ByName('relationname').AsString := RelationName;
737 qryRelConstraints.ExecQuery;
738 while not qryRelConstraints.Eof do
739 begin
740 Constraint := '';
741 FMetaData.Strings[FMetaData.Count - 1] := FMetaData.Strings[FMetaData.Count - 1] + ',';
742 { If the name of the constraint is not INTEG..., print it }
743 if Pos('INTEG', qryRelConstraints.FieldByName('RDB$CONSTRAINT_NAME').AsString) <> 1 then
744 Constraint := Constraint + 'CONSTRAINT ' +
745 QuoteIdentifier(
746 qryRelConstraints.FieldByName('RDB$CONSTRAINT_NAME').AsString);
747
748
749 if Pos('PRIMARY', qryRelConstraints.FieldByName('RDB$CONSTRAINT_TYPE').AsString) = 1 then
750 begin
751 FMetaData.Add(Constraint + Format(' PRIMARY KEY (%s)',
752 [GetIndexSegments(qryRelConstraints.FieldByName('RDB$INDEX_NAME').AsString)]));
753 end
754 else
755 if Pos('UNIQUE', qryRelConstraints.FieldByName('RDB$CONSTRAINT_TYPE').AsString) = 1 then
756 begin
757 FMetaData.Add(Constraint + Format(' UNIQUE (%s)',
758 [GetIndexSegments(qryRelConstraints.FieldByName('RDB$INDEX_NAME').AsString)]));
759 end;
760 qryRelConstraints.Next;
761 end;
762 if ValidRelation then
763 begin
764 if TableType = 4 then
765 FMetaData.Add(' ) ON COMMIT PRESERVE ROWS ' + TERM)
766 else
767 FMetaData.Add(')' + TERM);
768 end;
769 finally
770 qryTables.Free;
771 qryPrecision.Free;
772 qryConstraints.Free;
773 qryRelConstraints.Free;
774 qryGenerators.Free;
775 end;
776 end;
777
778 { ExtractListView
779 Functional description
780 Show text of the specified view.
781 Use a SQL query to get the info and print it.
782 Note: This should also contain check option }
783
784 procedure TIBExtract.ExtractListView(ViewName: String);
785 const
786 ViewsSQL = 'SELECT * FROM RDB$RELATIONS REL ' +
787 ' WHERE ' +
788 ' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' +
789 ' NOT REL.RDB$VIEW_BLR IS NULL AND ' +
790 ' REL.RDB$RELATION_NAME = :VIEWNAME AND ' +
791 ' REL.RDB$FLAGS = 1 ' +
792 'ORDER BY REL.RDB$RELATION_ID ';
793
794 ColumnsSQL = 'SELECT * FROM RDB$RELATION_FIELDS RFR ' +
795 'WHERE ' +
796 ' RFR.RDB$RELATION_NAME = :RELATIONNAME ' +
797 'ORDER BY RFR.RDB$FIELD_POSITION ';
798
799 var
800 qryViews, qryColumns : TIBSQL;
801 RelationName, ColList : String;
802 begin
803 ColList := '';
804 qryViews := TIBSQL.Create(FDatabase);
805 qryColumns := TIBSQL.Create(FDatabase);
806 try
807 qryViews.SQL.Add(ViewsSQL);
808 qryViews.Params.ByName('viewname').AsString := ViewName;
809 qryViews.ExecQuery;
810 while not qryViews.Eof do
811 begin
812 FMetaData.Add('');
813 RelationName := QuoteIdentifier(
814 qryViews.FieldByName('RDB$RELATION_NAME').AsString);
815 FMetaData.Add(Format('%s/* View: %s, Owner: %s */%s', [
816 RelationName,
817 Trim(qryViews.FieldByName('RDB$OWNER_NAME').AsString)]));
818 FMetaData.Add('');
819 FMetaData.Add(Format('CREATE VIEW %s (', [RelationName]));
820
821 { Get Column List}
822 qryColumns.SQL.Add(ColumnsSQL);
823 qryColumns.Params.ByName('relationname').AsString := RelationName;
824 qryColumns.ExecQuery;
825 while not qryColumns.Eof do
826 begin
827 ColList := ColList + QuoteIdentifier(
828 qryColumns.FieldByName('RDB$FIELD_NAME').AsString);
829 qryColumns.Next;
830 if not qryColumns.Eof then
831 ColList := ColList + ', ';
832 end;
833 FMetaData.Add(ColList + ') AS');
834 FMetaData.Add(qryViews.FieldByName('RDB$VIEW_SOURCE').AsString + Term);
835 qryViews.Next;
836 end;
837 finally
838 qryViews.Free;
839 qryColumns.Free;
840 end;
841 end;
842
843 function TIBExtract.GetCharacterSets(CharSetId, Collation: integer;
844 CollateOnly: Boolean): String;
845 var
846 CharSetSQL : TIBSQL;
847 DidActivate : Boolean;
848 begin
849 Result := '';
850 if not FTransaction.Active then
851 begin
852 FTransaction.StartTransaction;
853 DidActivate := true;
854 end
855 else
856 DidActivate := false;
857 CharSetSQL := TIBSQL.Create(FDatabase);
858 try
859 if Collation <> 0 then
860 begin
861 CharSetSQL.SQL.Add(CollationSQL);
862 CharSetSQL.Params.ByName('Char_Set_Id').AsInteger := CharSetId;
863 CharSetSQL.Params.ByName('Collation').AsInteger := Collation;
864 CharSetSQL.ExecQuery;
865
866 { Is specified collation the default collation for character set? }
867 if (Trim(CharSetSQL.FieldByName('RDB$DEFAULT_COLLATE_NAME').AsString) =
868 Trim(CharSetSQL.FieldByName('RDB$COLLATION_NAME').AsString)) then
869 begin
870 if not CollateOnly then
871 Result := ' CHARACTER SET ' + Trim(CharSetSQL.FieldByName('RDB$CHARACTER_SET_NAME').AsString);
872 end
873 else
874 if CollateOnly then
875 Result := ' COLLATE ' + Trim(CharSetSQL.FieldByName('RDB$COLLATION_NAME').AsString)
876 else
877 Result := ' CHARACTER SET ' +
878 Trim(CharSetSQL.FieldByName('RDB$CHARACTER_SET_NAME').AsString) +
879 ' COLLATE ' +
880 Trim(CharSetSQL.FieldByName('RDB$COLLATION_NAME').AsString);
881 end
882 else
883 if CharSetId <> 0 then
884 begin
885 CharSetSQL.SQL.Add(NonCollationSQL);
886 CharSetSQL.Params.ByName('CharSetId').AsShort := CharSetId;
887 CharSetSQL.ExecQuery;
888 Result := ' CHARACTER SET ' + Trim(CharSetSQL.FieldByName('RDB$CHARACTER_SET_NAME').AsString);
889 end;
890 finally
891 CharSetSQL.Free;
892 end;
893 if DidActivate then
894 FTransaction.Commit;
895 end;
896
897 procedure TIBExtract.Add2MetaData(const Msg: string; IsError: boolean);
898 begin
899 FMetaData.Add(Msg);
900 end;
901
902 function TIBExtract.GetDatabase: TIBDatabase;
903 begin
904 result := FDatabase;
905 end;
906
907 { GetIndexSegments
908 Functional description
909 returns the list of columns in an index. }
910
911 function TIBExtract.GetIndexSegments(indexname: String): String;
912 const
913 IndexNamesSQL =
914 'SELECT * FROM RDB$INDEX_SEGMENTS SEG ' +
915 'WHERE SEG.RDB$INDEX_NAME = :INDEXNAME ' +
916 'ORDER BY SEG.RDB$FIELD_POSITION';
917
918 var
919 qryColNames : TIBSQL;
920 begin
921 { Query to get column names }
922 Result := '';
923 qryColNames := TIBSQL.Create(FDatabase);
924 try
925 qryColNames.SQL.Add(IndexNamesSQL);
926 qryColNames.Params.ByName('IndexName').AsString := IndexName;
927 qryColNames.ExecQuery;
928 while not qryColNames.Eof do
929 begin
930 { Place a comma and a blank between each segment column name }
931
932 Result := Result + QuoteIdentifier(
933 qryColNames.FieldByName('RDB$FIELD_NAME').AsString);
934 qryColNames.Next;
935 if not qryColNames.Eof then
936 Result := Result + ', ';
937 end;
938 finally
939 qryColNames.Free;
940 end;
941 end;
942
943 function TIBExtract.GetTransaction: TIBTransaction;
944 begin
945 Result := FTransaction;
946 end;
947
948 function TIBExtract.GetTriggerType(TypeID: Int64): string;
949 const
950 AllDDLTriggers = $7FFFFFFFFFFFDFFF shr 1;
951 var separator: string;
952 i: integer;
953
954 function GetDDLEvent(Phase: TTriggerPhase; ObjectName: string): string;
955 begin
956 Result := '';
957 case Phase of
958 tpCreate:
959 Result := separator + 'CREATE ' + ObjectName;
960 tpAlter:
961 Result := separator + 'ALTER ' + ObjectName;
962 tpDrop:
963 Result := separator + 'Drop ' + ObjectName;
964 end;
965 if Result <> '' then
966 separator := ' OR ';
967 end;
968
969 begin
970 if TypeID and $2000 <> 0 then
971 {database trigger}
972 begin
973 Result := 'ON ';
974 case TypeID of
975 $2000:
976 Result += 'CONNECT';
977 $2001:
978 Result += 'DISCONNECT';
979 $2002:
980 Result +='TRANSACTION START';
981 $2003:
982 Result += 'TRANSACTION COMMIT';
983 $2004:
984 Result += 'TRANSACTION ROLLBACK';
985 end;
986 end
987 else
988 if TypeID and $4000 <> 0 then
989 {DDL Trigger}
990 begin
991 if TypeID and $01 <> 0 then
992 Result := 'AFTER '
993 else
994 Result := 'BEFORE ';
995 TypeID := TypeID shr 1;
996 separator := '';
997 i := 0;
998 if TypeID = AllDDLTriggers then
999 Result += 'ANY DDL STATEMENT'
1000 else
1001 repeat
1002 if (DDLTriggers[i].Bits > 0) and (TypeID and $01 <> 0) then
1003 Result += GetDDLEvent(DDLTriggers[i].Bit1,DDLTriggers[i].ObjectName);
1004
1005 if (DDLTriggers[i].Bits > 1) and (TypeID and $02 <> 0) then
1006 Result += GetDDLEvent(DDLTriggers[i].Bit2,DDLTriggers[i].ObjectName);
1007
1008 if (DDLTriggers[i].Bits > 2) and (TypeID and $04 <> 0) then
1009 Result += GetDDLEvent(DDLTriggers[i].Bit3,DDLTriggers[i].ObjectName);
1010 TypeID := TypeID shr DDLTriggers[i].Bits;
1011 Inc(i);
1012 until TypeID = 0;
1013 end
1014 else
1015 {Normal Trigger}
1016 begin
1017 Inc(TypeID);
1018 if TypeID and $01 <> 0 then
1019 Result := 'AFTER '
1020 else
1021 Result := 'BEFORE ';
1022 TypeID := TypeID shr 1;
1023 separator := '';
1024 repeat
1025 Result += separator;
1026 separator := ' or ';
1027 case TypeID and $03 of
1028 1:
1029 Result += 'INSERT';
1030 2:
1031 Result += 'UPDATE';
1032 3:
1033 Result += 'DELETE';
1034 end;
1035 TypeID := TypeID shr 2;
1036 until TypeID = 0
1037 end
1038 end;
1039
1040 { ListAllGrants
1041 Functional description
1042 Print the permissions on all user tables.
1043 Get separate permissions on table/views and then procedures }
1044
1045 procedure TIBExtract.ListGrants(ExtractTypes: TExtractTypes);
1046 const
1047 SecuritySQL = 'SELECT * FROM RDB$RELATIONS ' +
1048 'WHERE ' +
1049 ' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' +
1050 ' RDB$SECURITY_CLASS STARTING WITH ''SQL$'' ' +
1051 'ORDER BY RDB$RELATION_NAME';
1052
1053 DomainSQL = 'select RDB$FIELD_NAME from RDB$FIELDS '+
1054 'where RDB$SYSTEM_FLAG <> 1 and RDB$FIELD_NAME not Similar to ''RDB$%|SEC$%|MON$%|SQL$%'' '+
1055 'order BY RDB$FIELD_NAME';
1056
1057 CharacterSetSQL = 'Select * From RDB$CHARACTER_SETS '+
1058 'Where RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL ' +
1059 'Order by RDB$CHARACTER_SET_NAME';
1060
1061 CollationsSQL = 'Select * From RDB$COLLATIONS '+
1062 'Where RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL ' +
1063 'Order by RDB$COLLATION_NAME';
1064
1065 ProcedureSQL = 'select * from RDB$PROCEDURES '+
1066 'Where RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL ' +
1067 'Order BY RDB$PROCEDURE_NAME';
1068
1069 PackagesSQL = 'select * from RDB$PACKAGES '+
1070 'Where RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL ' +
1071 'Order BY RDB$PACKAGE_NAME';
1072
1073 ExceptionSQL = 'select * from RDB$EXCEPTIONS '+
1074 'Where RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL ' +
1075 'Order BY RDB$EXCEPTION_NAME';
1076
1077 GeneratorSQL = 'select * from RDB$GENERATORS '+
1078 'Where RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL ' +
1079 'Order BY RDB$GENERATOR_NAME';
1080
1081 MetadataGrantsSQL =
1082 'Select PR.RDB$USER, PR.RDB$USER_TYPE, '+
1083 'T.RDB$TYPE_NAME as USER_TYPE_NAME, '+
1084 'Case PR.RDB$PRIVILEGE '+
1085 ' When ''C'' then ''CREATE'' '+
1086 ' When ''O'' then ''DROP ANY'' '+
1087 ' When ''L'' then ''ALTER ANY'' End as Privilege, '+
1088 'Case PR.RDB$RELATION_NAME '+
1089 ' When ''SQL$COLLATIONS'' then ''COLLATION'' '+
1090 ' When ''SQL$CHARSETS'' then ''CHARACTER SET'' '+
1091 ' When ''SQL$DATABASE'' then ''DATABASE'' '+
1092 ' When ''SQL$DOMAINS'' then ''DOMAIN'' '+
1093 ' When ''SQL$EXCEPTIONS'' then ''EXCEPTION'' '+
1094 ' When ''SQL$FILTERS'' then ''FILTER'' '+
1095 ' When ''SQL$FUNCTIONS'' then ''FUNCTION'' '+
1096 ' When ''SQL$GENERATORS'' then ''GENERATOR'' '+
1097 ' When ''SQL$PACKAGES'' then ''PACKAGE'' '+
1098 ' When ''SQL$PROCEDURES'' then ''PROCEDURE'' '+
1099 ' When ''SQL$ROLES'' then ''ROLE'' '+
1100 ' When ''SQL$VIEWS'' then ''VIEW'' '+
1101 ' When ''SQL$TABLES'' then ''TABLE'' End as METAOBJECTNAME,'+
1102
1103 'case when coalesce(RDB$GRANT_OPTION,0) <> 0 then '' WITH GRANT OPTION'' '+
1104 'ELSE '''' End as GRANTOPTION '+
1105 'FROM RDB$USER_PRIVILEGES PR '+
1106 'JOIN RDB$TYPES T On T.RDB$TYPE = PR.RDB$USER_TYPE and T.RDB$FIELD_NAME = ''RDB$OBJECT_TYPE'' '+
1107 'Where PR.RDB$RELATION_NAME like ''SQL$%'' and PR.RDB$PRIVILEGE in (''L'',''C'',''O'')';
1108
1109 var
1110 qryRoles : TIBSQL;
1111 RelationName : String;
1112 begin
1113 ListRoles;
1114 qryRoles := TIBSQL.Create(FDatabase);
1115 try
1116 { This version of cursor gets only sql tables identified by security class
1117 and misses views, getting only null view_source }
1118
1119 FMetaData.Add('');
1120 FMetaData.Add('/* Grant permissions for this database */');
1121 FMetaData.Add('');
1122
1123 try
1124 qryRoles.SQL.Text := SecuritySQL;
1125 qryRoles.ExecQuery;
1126 while not qryRoles.Eof do
1127 begin
1128 RelationName := Trim(qryRoles.FieldByName('rdb$relation_Name').AsString);
1129 ShowGrants(RelationName, Term, not (etGrantsToUser in ExtractTypes));
1130 qryRoles.Next;
1131 end;
1132 finally
1133 qryRoles.Close;
1134 end;
1135
1136 if etGrantsToUser in ExtractTypes then
1137 ShowGrantRoles(Term);
1138
1139 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION12 then
1140 begin
1141 qryRoles.SQL.Text := DomainSQL;
1142 qryRoles.ExecQuery;
1143 try
1144 while not qryRoles.Eof do
1145 begin
1146 ShowGrants(Trim(qryRoles.FieldByName('RDB$FIELD_NAME').AsString), Term,
1147 not (etGrantsToUser in ExtractTypes));
1148 qryRoles.Next;
1149 end;
1150 finally
1151 qryRoles.Close;
1152 end;
1153
1154 qryRoles.SQL.Text := CharacterSetSQL;
1155 qryRoles.ExecQuery;
1156 try
1157 while not qryRoles.Eof do
1158 begin
1159 ShowGrants(Trim(qryRoles.FieldByName('RDB$CHARACTER_SET_NAME').AsString), Term,
1160 not (etGrantsToUser in ExtractTypes));
1161 qryRoles.Next;
1162 end;
1163 finally
1164 qryRoles.Close;
1165 end;
1166
1167 qryRoles.SQL.Text := CollationsSQL;
1168 qryRoles.ExecQuery;
1169 try
1170 while not qryRoles.Eof do
1171 begin
1172 ShowGrants(Trim(qryRoles.FieldByName('RDB$COLLATION_NAME').AsString), Term,
1173 not (etGrantsToUser in ExtractTypes));
1174 qryRoles.Next;
1175 end;
1176 finally
1177 qryRoles.Close;
1178 end;
1179
1180 qryRoles.SQL.Text := ExceptionSQL;
1181 qryRoles.ExecQuery;
1182 try
1183 while not qryRoles.Eof do
1184 begin
1185 ShowGrants(Trim(qryRoles.FieldByName('RDB$EXCEPTION_NAME').AsString), Term,
1186 not (etGrantsToUser in ExtractTypes));
1187 qryRoles.Next;
1188 end;
1189 finally
1190 qryRoles.Close;
1191 end;
1192
1193 qryRoles.SQL.Text := GeneratorSQL;
1194 qryRoles.ExecQuery;
1195 try
1196 while not qryRoles.Eof do
1197 begin
1198 ShowGrants(Trim(qryRoles.FieldByName('RDB$GENERATOR_NAME').AsString), Term,
1199 not (etGrantsToUser in ExtractTypes));
1200 qryRoles.Next;
1201 end;
1202 finally
1203 qryRoles.Close;
1204 end;
1205 end;
1206
1207 qryRoles.SQL.Text := ProcedureSQL;
1208 qryRoles.ExecQuery;
1209 try
1210 while not qryRoles.Eof do
1211 begin
1212 ShowGrants(Trim(qryRoles.FieldByName('RDB$PROCEDURE_NAME').AsString), Term,
1213 not (etGrantsToUser in ExtractTypes));
1214 qryRoles.Next;
1215 end;
1216 finally
1217 qryRoles.Close;
1218 end;
1219
1220 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION12 then
1221 begin
1222 qryRoles.SQL.Text := PackagesSQL;
1223 qryRoles.ExecQuery;
1224 try
1225 while not qryRoles.Eof do
1226 begin
1227 ShowGrants(Trim(qryRoles.FieldByName('RDB$PACKAGE_NAME').AsString), Term,
1228 not (etGrantsToUser in ExtractTypes));
1229 qryRoles.Next;
1230 end;
1231 finally
1232 qryRoles.Close;
1233 end;
1234 end;
1235
1236 {Metadata Grants}
1237 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION12 then
1238 begin
1239 qryRoles.SQL.Text := MetadataGrantsSQL;
1240 qryRoles.ExecQuery;
1241 while not qryRoles.Eof do
1242 begin
1243 if (etGrantsToUser in ExtractTypes) or
1244 (qryRoles.FieldByName('RDB$USER_TYPE').AsInteger <> obj_user) or
1245 (qryRoles.FieldByName('RDB$USER').AsString = 'PUBLIC') then
1246 FMetaData.Add(Format('GRANT %s %s TO %s %s %s%s', [
1247 qryRoles.FieldByName('Privilege').AsString,
1248 qryRoles.FieldByName('METAOBJECTNAME').AsString,
1249 qryRoles.FieldByName('USER_TYPE_NAME').AsString,
1250 QuoteIdentifier(qryRoles.FieldByName('RDB$USER').AsString),
1251 qryRoles.FieldByName('GRANTOPTION').AsString,
1252 Term]));
1253 qryRoles.Next;
1254 end;
1255 qryRoles.Close;
1256 end;
1257 finally
1258 qryRoles.Free;
1259 end;
1260 end;
1261
1262 procedure TIBExtract.ListPackages(PackageDDLType: TPackageDDLType;
1263 PackageName: string; IncludeGrants: boolean);
1264 const
1265 PackageSQL = 'Select * From RDB$PACKAGES order by RDB$PACKAGE_NAME';
1266 PackageNameSQL = 'Select * From RDB$PACKAGES Where RDB$PACKAGE_NAME = :PackageName order by RDB$PACKAGE_NAME';
1267 PackageHeaderSQL = 'CREATE PACKAGE %s%sAS%s';
1268 PackageBodySQL = 'CREATE PACKAGE BODY %s%sAS%s';
1269 var
1270 qryPackages : TIBSQL;
1271 Header : Boolean;
1272 SList : TStrings;
1273 aPackageName: string;
1274 begin
1275 Header := true;
1276 qryPackages := TIBSQL.Create(FDatabase);
1277 SList := TStringList.Create;
1278 try
1279 if PackageName = '' then
1280 qryPackages.SQL.Text := PackageSQL
1281 else
1282 begin
1283 qryPackages.SQL.Text := PackageNameSQL;
1284 qryPackages.ParamByName('PackageName').AsString := PackageName;
1285 end;
1286
1287 qryPackages.ExecQuery;
1288 while not qryPackages.Eof do
1289 begin
1290 if Header then
1291 begin
1292 FMetaData.Add('COMMIT WORK;');
1293 FMetaData.Add('SET AUTODDL OFF;');
1294 FMetaData.Add(Format('SET TERM %s %s', [ProcTerm, Term]));
1295 FMetaData.Add(Format('%s/* Package Definitions */%s', [LineEnding, LineEnding]));
1296 Header := false;
1297 end;
1298
1299 aPackageName := qryPackages.FieldByName('RDB$PACKAGE_NAME').AsString;
1300 if PackageDDLType in [paHeader,paBoth] then
1301 begin
1302 FMetaData.Add(Format(PackageHeaderSQL,[aPackageName,
1303 LineEnding,LineEnding]));
1304 SList.Text := qryPackages.FieldByName('RDB$PACKAGE_HEADER_SOURCE').AsString;
1305 SList.Add(Format(' %s%s', [ProcTerm, LineEnding]));
1306 FMetaData.AddStrings(SList);
1307 end;
1308
1309 if PackageDDLType in [paBody,paBoth] then
1310 begin
1311 FMetaData.Add(Format(PackageBodySQL,[aPackageName,
1312 LineEnding,LineEnding]));
1313 SList.Text := qryPackages.FieldByName('RDB$PACKAGE_BODY_SOURCE').AsString;
1314 SList.Add(Format(' %s%s', [ProcTerm, LineEnding]));
1315 FMetaData.AddStrings(SList);
1316 end;
1317
1318 if IncludeGrants then
1319 ShowGrantsTo(aPackageName,obj_package,ProcTerm);
1320 qryPackages.Next;
1321 end;
1322 qryPackages.Close;
1323
1324 if not Header then
1325 begin
1326 FMetaData.Add(Format('SET TERM %s %s', [Term, ProcTerm]));
1327 FMetaData.Add('COMMIT WORK;');
1328 FMetaData.Add('SET AUTODDL ON;');
1329 end;
1330 finally
1331 SList.Free;
1332 qryPackages.Free;
1333 end;
1334 end;
1335
1336 { ListAllProcs
1337 Functional description
1338 Shows text of a stored procedure given a name.
1339 or lists procedures if no argument.
1340 Since procedures may reference each other, we will create all
1341 dummy procedures of the correct name, then alter these to their
1342 correct form.
1343 Add the parameter names when these procedures are created.
1344
1345 procname -- Name of procedure to investigate }
1346
1347 procedure TIBExtract.ListProcs(ProcDDLType: TProcDDLType;
1348 ProcedureName: String; IncludeGrants: boolean);
1349 const
1350 CreateProcedureStr1 = 'CREATE PROCEDURE %s ';
1351 CreateProcedureStr2 = 'BEGIN EXIT; END %s%s';
1352 CreateProcedureStr3 = 'BEGIN SUSPEND; EXIT; END %s%s';
1353 ProcedureSQL = {Order procedures by dependency order and then procedure name}
1354 'with recursive Procs as ( ' +
1355 'Select RDB$PROCEDURE_NAME, 1 as ProcLevel from RDB$PROCEDURES ' +
1356 'UNION ALL ' +
1357 'Select D.RDB$DEPENDED_ON_NAME, ProcLevel + 1 From RDB$DEPENDENCIES D ' +
1358 'JOIN Procs on Procs.RDB$PROCEDURE_NAME = D.RDB$DEPENDENT_NAME ' +
1359 ' and Procs.RDB$PROCEDURE_NAME <> D.RDB$DEPENDED_ON_NAME ' +
1360 'JOIN RDB$PROCEDURES P On P.RDB$PROCEDURE_NAME = D.RDB$DEPENDED_ON_NAME ' +
1361 ' ) ' +
1362 'SELECT * FROM RDB$PROCEDURES P ' +
1363 'JOIN ( ' +
1364 'Select RDB$PROCEDURE_NAME, max(ProcLevel) as ProcLevel From Procs ' +
1365 'Group By RDB$PROCEDURE_NAME) A On A.RDB$PROCEDURE_NAME = P.RDB$PROCEDURE_NAME ' +
1366 'Order by A.ProcLevel desc, P.RDB$PROCEDURE_NAME asc';
1367
1368 ProcedureSQLODS12 = {Order procedures by dependency order and then procedure name}
1369 'with recursive Procs as ( ' +
1370 'Select RDB$PROCEDURE_NAME, 1 as ProcLevel from RDB$PROCEDURES ' +
1371 'UNION ALL ' +
1372 'Select D.RDB$DEPENDED_ON_NAME, ProcLevel + 1 From RDB$DEPENDENCIES D ' +
1373 'JOIN Procs on Procs.RDB$PROCEDURE_NAME = D.RDB$DEPENDENT_NAME ' +
1374 ' and Procs.RDB$PROCEDURE_NAME <> D.RDB$DEPENDED_ON_NAME ' +
1375 'JOIN RDB$PROCEDURES P On P.RDB$PROCEDURE_NAME = D.RDB$DEPENDED_ON_NAME ' +
1376 ' ) ' +
1377 'SELECT * FROM RDB$PROCEDURES P ' +
1378 'JOIN ( ' +
1379 'Select RDB$PROCEDURE_NAME, max(ProcLevel) as ProcLevel From Procs ' +
1380 'Group By RDB$PROCEDURE_NAME) A On A.RDB$PROCEDURE_NAME = P.RDB$PROCEDURE_NAME ' +
1381 'Where P.RDB$PACKAGE_NAME is NULL '+
1382 'Order by A.ProcLevel desc, P.RDB$PROCEDURE_NAME asc';
1383 ProcedureNameSQL =
1384 'SELECT * FROM RDB$PROCEDURES ' +
1385 'WHERE RDB$PROCEDURE_NAME = :ProcedureName ' +
1386 'ORDER BY RDB$PROCEDURE_NAME';
1387
1388 var
1389 qryProcedures : TIBSQL;
1390 ProcName : String;
1391 SList : TStrings;
1392 Header : Boolean;
1393
1394 begin
1395
1396 Header := true;
1397 qryProcedures := TIBSQL.Create(FDatabase);
1398 SList := TStringList.Create;
1399 try
1400 if ProcedureName = '' then
1401 begin
1402 if DatabaseInfo.ODSMajorVersion < ODS_VERSION12 then
1403 qryProcedures.SQL.Text := ProcedureSQL
1404 else
1405 qryProcedures.SQL.Text := ProcedureSQLODS12;
1406 end
1407 else
1408 begin
1409 qryProcedures.SQL.Text := ProcedureNameSQL;
1410 qryProcedures.Params.ByName('ProcedureName').AsString := ProcedureName;
1411 end;
1412
1413 qryProcedures.ExecQuery;
1414 while not qryProcedures.Eof do
1415 begin
1416 if Header then
1417 begin
1418 FMetaData.Add('COMMIT WORK;');
1419 FMetaData.Add('SET AUTODDL OFF;');
1420 FMetaData.Add(Format('SET TERM %s %s', [ProcTerm, Term]));
1421 FMetaData.Add(Format('%s/* Stored procedures */%s', [LineEnding, LineEnding]));
1422 Header := false;
1423 end;
1424 ProcName := Trim(qryProcedures.FieldByName('RDB$PROCEDURE_NAME').AsString);
1425
1426 case ProcDDLType of
1427 pdCreateStub:
1428 begin
1429 FMetaData.Add(Format(CreateProcedureStr1, [QuoteIdentifier(
1430 ProcName)]));
1431 GetProcedureArgs(ProcName);
1432 if qryProcedures.FieldByName('RDB$PROCEDURE_TYPE').AsInteger = 1 then
1433 FMetaData.Add(Format(CreateProcedureStr3, [ProcTerm, LineEnding]))
1434 else
1435 FMetaData.Add(Format(CreateProcedureStr2, [ProcTerm, LineEnding]));
1436 end;
1437
1438 pdCreateProc:
1439 begin
1440 FMetaData.Add(Format(CreateProcedureStr1, [QuoteIdentifier(
1441 ProcName)]));
1442 GetProcedureArgs(ProcName);
1443 if not qryProcedures.FieldByName('RDB$PROCEDURE_SOURCE').IsNull then
1444 begin
1445 SList.Text := qryProcedures.FieldByName('RDB$PROCEDURE_SOURCE').AsString;
1446 SList.Add(Format(' %s%s', [ProcTerm, LineEnding]));
1447 FMetaData.AddStrings(SList);
1448 end
1449 else
1450 FMetaData.Add(Format(CreateProcedureStr2, [ProcTerm, LineEnding]));
1451 end;
1452
1453 pdAlterProc:
1454 begin
1455 FMetaData.Add(Format('%sALTER PROCEDURE %s ', [LineEnding,
1456 QuoteIdentifier( ProcName)]));
1457 GetProcedureArgs(ProcName);
1458
1459 if not qryProcedures.FieldByName('RDB$PROCEDURE_SOURCE').IsNull then
1460 begin
1461 SList.Text := qryProcedures.FieldByName('RDB$PROCEDURE_SOURCE').AsString;
1462 SList.Add(Format(' %s%s', [ProcTerm, LineEnding]));
1463 FMetaData.AddStrings(SList);
1464 end
1465 else
1466 FMetaData.Add(Format(CreateProcedureStr2, [ProcTerm, LineEnding]));
1467 end;
1468 end;
1469 if IncludeGrants then
1470 ShowGrantsTo(ProcName,obj_procedure,ProcTerm);
1471 qryProcedures.Next;
1472 end;
1473 qryProcedures.Close;
1474
1475 if not Header then
1476 begin
1477 FMetaData.Add(Format('SET TERM %s %s', [Term, ProcTerm]));
1478 FMetaData.Add('COMMIT WORK;');
1479 FMetaData.Add('SET AUTODDL ON;');
1480 end;
1481 finally
1482 qryProcedures.Free;
1483 SList.Free;
1484 end;
1485 end;
1486
1487 { ListAllTables
1488 Functional description
1489 Extract the names of all user tables from
1490 rdb$relations. Filter SQL tables by
1491 security class after we fetch them
1492 Parameters: flag -- 0, get all tables }
1493
1494 procedure TIBExtract.ListAllTables(flag: Boolean);
1495 const
1496 TableSQL =
1497 'SELECT * FROM RDB$RELATIONS ' +
1498 'WHERE ' +
1499 ' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' +
1500 ' RDB$VIEW_BLR IS NULL ' +
1501 'ORDER BY RDB$RELATION_NAME';
1502
1503 var
1504 qryTables : TIBSQL;
1505 begin
1506 { This version of cursor gets only sql tables identified by security class
1507 and misses views, getting only null view_source }
1508
1509 qryTables := TIBSQL.Create(FDatabase);
1510 try
1511 qryTables.SQL.Text := TableSQL;
1512 qryTables.ExecQuery;
1513 while not qryTables.Eof do
1514 begin
1515 if ((qryTables.FieldByName('RDB$FLAGS').AsInteger <> 1) and
1516 (not Flag)) then
1517 continue;
1518 if flag or (Pos('SQL$', qryTables.FieldByName('RDB$SECURITY_CLASS').AsString) <> 1) then
1519 ExtractListTable(qryTables.FieldByName('RDB$RELATION_NAME').AsString,
1520 '', false);
1521
1522 qryTables.Next;
1523 end;
1524 finally
1525 qryTables.Free;
1526 end;
1527 end;
1528
1529 { ListAllTriggers
1530 Functional description
1531 Lists triggers in general on non-system
1532 tables with sql source only. }
1533
1534 procedure TIBExtract.ListTriggers(ObjectName: String; ExtractTypes: TExtractTypes
1535 );
1536 const
1537 { Query gets the trigger info for non-system triggers with
1538 source that are not part of an SQL constraint }
1539
1540 TriggerSQL =
1541 'SELECT * FROM RDB$TRIGGERS TRG Left Outer JOIN RDB$RELATIONS REL ON ' +
1542 ' TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME ' +
1543 'WHERE ' +
1544 ' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' +
1545 ' NOT EXISTS (SELECT * FROM RDB$CHECK_CONSTRAINTS CHK WHERE ' +
1546 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME) ' +
1547 'ORDER BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, ' +
1548 ' TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME';
1549
1550 TriggerNameSQL =
1551 'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$RELATIONS REL ON ' +
1552 ' TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME ' +
1553 'WHERE ' +
1554 ' REL.RDB$RELATION_NAME = :TableName AND ' +
1555 ' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' +
1556 ' NOT EXISTS (SELECT * FROM RDB$CHECK_CONSTRAINTS CHK WHERE ' +
1557 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME) ' +
1558 'ORDER BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, ' +
1559 ' TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME';
1560
1561 TriggerByNameSQL =
1562 'SELECT * FROM RDB$TRIGGERS TRG Left Outer JOIN RDB$RELATIONS REL ON ' +
1563 ' TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME ' +
1564 'WHERE ' +
1565 ' TRG.RDB$TRIGGER_NAME = :TriggerName AND ' +
1566 ' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' +
1567 ' NOT EXISTS (SELECT * FROM RDB$CHECK_CONSTRAINTS CHK WHERE ' +
1568 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME) ' +
1569 'ORDER BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, ' +
1570 ' TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME';
1571
1572 var
1573 Header : Boolean;
1574 TriggerName, RelationName, InActive: String;
1575 qryTriggers : TIBSQL;
1576 SList : TStrings;
1577 begin
1578 Header := true;
1579 SList := TStringList.Create;
1580 qryTriggers := TIBSQL.Create(FDatabase);
1581 try
1582 if ObjectName = '' then
1583 qryTriggers.SQL.Text := TriggerSQL
1584 else
1585 begin
1586 if etTable in ExtractTypes then
1587 begin
1588 qryTriggers.SQL.Text := TriggerNameSQL;
1589 qryTriggers.Params.ByName('TableName').AsString := ObjectName;
1590 end
1591 else
1592 begin
1593 qryTriggers.SQL.Text := TriggerByNameSQL;
1594 qryTriggers.Params.ByName('TriggerName').AsString := ObjectName;
1595 end;
1596 end;
1597 qryTriggers.ExecQuery;
1598 while not qryTriggers.Eof do
1599 begin
1600 SList.Clear;
1601 if Header then
1602 begin
1603 FMetaData.Add(Format('SET TERM %s %s%s', [Procterm, Term, LineEnding]));
1604 FMetaData.Add(Format('%s/* Triggers only will work for SQL triggers */%s',
1605 [LineEnding, LineEnding]));
1606 Header := false;
1607 end;
1608 TriggerName := qryTriggers.FieldByName('RDB$TRIGGER_NAME').AsString;
1609 RelationName := qryTriggers.FieldByName('RDB$RELATION_NAME').AsString;
1610 if qryTriggers.FieldByName('RDB$TRIGGER_INACTIVE').IsNull then
1611 InActive := 'INACTIVE'
1612 else
1613 if qryTriggers.FieldByName('RDB$TRIGGER_INACTIVE').AsInteger = 1 then
1614 InActive := 'INACTIVE'
1615 else
1616 InActive := 'ACTIVE';
1617
1618 if qryTriggers.FieldByName('RDB$FLAGS').AsInteger <> 1 then
1619 SList.Add('/* ');
1620
1621 {Database or Transaction trigger}
1622 SList.Add(Format('CREATE TRIGGER %s%s%s %s POSITION %d',
1623 [QuoteIdentifier( TriggerName),
1624 LineEnding, InActive,
1625 GetTriggerType(qryTriggers.FieldByName('RDB$TRIGGER_TYPE').AsInt64),
1626 qryTriggers.FieldByName('RDB$TRIGGER_SEQUENCE').AsInteger]));
1627
1628 if RelationName <> '' then
1629 SList.Add('ON ' + QuoteIdentifier( RelationName));
1630
1631 if not qryTriggers.FieldByName('RDB$TRIGGER_SOURCE').IsNull then
1632 SList.Add(qryTriggers.FieldByName('RDB$TRIGGER_SOURCE').AsString)
1633 else
1634 SList.Add('AS BEGIN EXIT; END');
1635 SList.Add(' ' + ProcTerm);
1636 if qryTriggers.FieldByName('RDB$FLAGS').AsInteger <> 1 then
1637 SList.Add(' */');
1638 FMetaData.AddStrings(SList);
1639 if etGrant in ExtractTypes then
1640 ShowGrantsTo(TriggerName,obj_trigger,ProcTerm);
1641 qryTriggers.Next;
1642 end;
1643 if not Header then
1644 begin
1645 FMetaData.Add('COMMIT WORK ' + ProcTerm);
1646 FMetaData.Add('SET TERM ' + Term + ProcTerm);
1647 end;
1648 finally
1649 qryTriggers.Free;
1650 SList.Free;
1651 end;
1652 end;
1653
1654 { ListCheck
1655 Functional description
1656 List check constraints for all objects to allow forward references }
1657
1658 procedure TIBExtract.ListCheck(ObjectName : String; ExtractType : TExtractType);
1659 const
1660 { Query gets the check clauses for triggers stored for check constraints }
1661 CheckSQL =
1662 'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$CHECK_CONSTRAINTS CHK ON ' +
1663 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME ' +
1664 'WHERE ' +
1665 ' TRG.RDB$TRIGGER_TYPE = 1 AND ' +
1666 ' EXISTS (SELECT RDB$CONSTRAINT_NAME FROM RDB$RELATION_CONSTRAINTS RELC WHERE ' +
1667 ' CHK.RDB$CONSTRAINT_NAME = RELC.RDB$CONSTRAINT_NAME) ' +
1668 'ORDER BY CHK.RDB$CONSTRAINT_NAME';
1669
1670 CheckNameSQL =
1671 'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$CHECK_CONSTRAINTS CHK ON ' +
1672 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME ' +
1673 'WHERE ' +
1674 ' TRG.RDB$RELATION_NAME = :TableName AND ' +
1675 ' TRG.RDB$TRIGGER_TYPE = 1 AND ' +
1676 ' EXISTS (SELECT RDB$CONSTRAINT_NAME FROM RDB$RELATION_CONSTRAINTS RELC WHERE ' +
1677 ' CHK.RDB$CONSTRAINT_NAME = RELC.RDB$CONSTRAINT_NAME) ' +
1678 'ORDER BY CHK.RDB$CONSTRAINT_NAME';
1679
1680 CheckByNameSQL =
1681 'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$CHECK_CONSTRAINTS CHK ON ' +
1682 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME ' +
1683 'WHERE ' +
1684 ' TRG.RDB$TRIGGER_NAME = :TriggerName AND ' +
1685 ' TRG.RDB$TRIGGER_TYPE = 1 AND ' +
1686 ' EXISTS (SELECT RDB$CONSTRAINT_NAME FROM RDB$RELATION_CONSTRAINTS RELC WHERE ' +
1687 ' CHK.RDB$CONSTRAINT_NAME = RELC.RDB$CONSTRAINT_NAME) ' +
1688 'ORDER BY CHK.RDB$CONSTRAINT_NAME';
1689
1690 var
1691 qryChecks : TIBSQL;
1692 SList : TStrings;
1693 RelationName : String;
1694 begin
1695 qryChecks := TIBSQL.Create(FDatabase);
1696 SList := TStringList.Create;
1697 try
1698 if ObjectName = '' then
1699 qryChecks.SQL.Text := CheckSQL
1700 else
1701 if ExtractType = etTable then
1702 begin
1703 qryChecks.SQL.Text := CheckNameSQL;
1704 qryChecks.Params.ByName('TableName').AsString := ObjectName;
1705 end
1706 else
1707 begin
1708 qryChecks.SQL.Text := CheckByNameSQL;
1709 qryChecks.Params.ByName('TriggerName').AsString := ObjectName;
1710 end;
1711 qryChecks.ExecQuery;
1712 while not qryChecks.Eof do
1713 begin
1714 SList.Clear;
1715 RelationName := qryChecks.FieldByName('RDB$RELATION_NAME').AsString;
1716 SList.Add(Format('ALTER TABLE %s ADD',
1717 [QuoteIdentifier( RelationName)]));
1718 if Pos('INTEG', qryChecks.FieldByName('RDB$CONSTRAINT_NAME').AsString) <> 1 then
1719 SList.Add(Format('%sCONSTRAINT %s ', [TAB,
1720 QuoteIdentifier( qryChecks.FieldByName('RDB$CONSTRAINT_NAME').AsString)]));
1721
1722 if not qryChecks.FieldByName('RDB$TRIGGER_SOURCE').IsNull then
1723 SList.Text := SList.Text + qryChecks.FieldByName('RDB$TRIGGER_SOURCE').AsString;
1724
1725 SList.Strings[SList.Count - 1] := SList.Strings[SList.Count - 1] + (Term) + LineEnding;
1726 FMetaData.AddStrings(SList);
1727 qryChecks.Next;
1728 end;
1729 finally
1730 qryChecks.Free;
1731 SList.Free;
1732 end;
1733 end;
1734
1735 { ListCreateDb
1736 Functional description
1737 Print the create database command if requested. At least put
1738 the page size in a comment with the extracted db name }
1739
1740 procedure TIBExtract.ListCreateDb(TargetDb : String);
1741 const
1742 CharInfoSQL =
1743 'SELECT * FROM RDB$DATABASE DBP ' +
1744 'WHERE NOT DBP.RDB$CHARACTER_SET_NAME IS NULL ' +
1745 ' AND DBP.RDB$CHARACTER_SET_NAME <> '' ''';
1746
1747 FilesSQL =
1748 'select * from RDB$FILES ' +
1749 'order BY RDB$SHADOW_NUMBER, RDB$FILE_SEQUENCE';
1750
1751 LogsSQL =
1752 'SELECT * FROM RDB$LOG_FILES ' +
1753 'ORDER BY RDB$FILE_FLAGS, RDB$FILE_SEQUENCE';
1754
1755 var
1756 NoDb, First, FirstFile, HasWal, SetUsed : Boolean;
1757 Buffer : String;
1758 qryDB : TIBSQL;
1759 FileFlags, FileLength, FileSequence, FileStart : Integer;
1760
1761 function GetLongDatabaseInfo(DatabaseInfoCommand: Integer): LongInt;
1762 begin
1763 with Database.Attachment.GetDBInformation([DatabaseInfoCommand]) do
1764 if (Count > 0) and (Items[0].GetItemType = DatabaseInfoCommand) then
1765 Result := Items[0].AsInteger
1766 else
1767 IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
1768 end;
1769
1770 begin
1771 NoDb := FALSE;
1772 First := TRUE;
1773 FirstFile := TRUE;
1774 HasWal := FALSE;
1775 SetUsed := FALSE;
1776 Buffer := '';
1777 if TargetDb = '' then
1778 begin
1779 Buffer := '/* ';
1780 TargetDb := FDatabase.DatabaseName;
1781 NoDb := true;
1782 end;
1783 Buffer := Buffer + 'CREATE DATABASE ' + QuotedStr(TargetDb) + ' PAGE_SIZE ' +
1784 IntToStr(FDatabaseInfo.PageSize) + LineEnding;
1785 FMetaData.Add(Buffer);
1786 Buffer := '';
1787
1788 qryDB := TIBSQL.Create(FDatabase);
1789 try
1790 qryDB.SQL.Text := CharInfoSQL;
1791 qryDB.ExecQuery;
1792
1793 if not qryDB.EOF then
1794 Buffer := Format(' DEFAULT CHARACTER SET %s',
1795 [trim(qryDB.FieldByName('RDB$CHARACTER_SET_NAME').AsString)]);
1796 if NoDB then
1797 Buffer := Buffer + Term + ' */'
1798 else
1799 Buffer := Buffer + Term;
1800 FMetaData.Add(Buffer);
1801 qryDB.Close;
1802 {List secondary files and shadows as
1803 alter db and create shadow in comment}
1804 qryDB.SQL.Text := FilesSQL;
1805 qryDB.ExecQuery;
1806 while not qryDB.Eof do
1807 begin
1808 if First then
1809 begin
1810 FMetaData.Add(LineEnding + '/* Add secondary files in comments ');
1811 First := false;
1812 end; //end_if
1813
1814 if qryDB.FieldByName('RDB$FILE_FLAGS').IsNull then
1815 FileFlags := 0
1816 else
1817 FileFlags := qryDB.FieldByName('RDB$FILE_FLAGS').AsInteger;
1818 if qryDB.FieldByName('RDB$FILE_LENGTH').IsNull then
1819 FileLength := 0
1820 else
1821 FileLength := qryDB.FieldByName('RDB$FILE_LENGTH').AsInteger;
1822 if qryDB.FieldByName('RDB$FILE_SEQUENCE').IsNull then
1823 FileSequence := 0
1824 else
1825 FileSequence := qryDB.FieldByName('RDB$FILE_SEQUENCE').AsInteger;
1826 if qryDB.FieldByName('RDB$FILE_START').IsNull then
1827 FileStart := 0
1828 else
1829 FileStart := qryDB.FieldByName('RDB$FILE_START').AsInteger;
1830
1831 { Pure secondary files }
1832 if FileFlags = 0 then
1833 begin
1834 Buffer := Format('%sALTER DATABASE ADD FILE ''%s''',
1835 [LineEnding, qryDB.FieldByName('RDB$FILE_NAME').AsString]);
1836 if FileStart <> 0 then
1837 Buffer := Buffer + Format(' STARTING %d', [FileStart]);
1838 if FileLength <> 0 then
1839 Buffer := Buffer + Format(' LENGTH %d', [FileLength]);
1840 FMetaData.Add(Buffer);
1841 end; //end_if
1842 if (FileFlags and FILE_cache) <> 0 then
1843 FMetaData.Add(Format('%sALTER DATABASE ADD CACHE ''%s'' LENGTH %d',
1844 [LineEnding, qryDB.FieldByName('RDB$FILE_NAME').AsString, FileLength]));
1845
1846 Buffer := '';
1847 if (FileFlags and FILE_shadow) <> 0 then
1848 begin
1849 if FileSequence <> 0 then
1850 Buffer := Format('%sFILE ''%s''',
1851 [TAB, qryDB.FieldByName('RDB$FILE_NAME').AsString])
1852 else
1853 begin
1854 Buffer := Format('%sCREATE SHADOW %d ''%s'' ',
1855 [LineEnding, qryDB.FieldByName('RDB$SHADOW_NUMBER').AsInteger,
1856 qryDB.FieldByName('RDB$FILE_NAME').AsString]);
1857 if (FileFlags and FILE_inactive) <> 0 then
1858 Buffer := Buffer + 'INACTIVE ';
1859 if (FileFlags and FILE_manual) <> 0 then
1860 Buffer := Buffer + 'MANUAL '
1861 else
1862 Buffer := Buffer + 'AUTO ';
1863 if (FileFlags and FILE_conditional) <> 0 then
1864 Buffer := Buffer + 'CONDITIONAL ';
1865 end; //end_else
1866 if FileLength <> 0 then
1867 Buffer := Buffer + Format('LENGTH %d ', [FileLength]);
1868 if FileStart <> 0 then
1869 Buffer := Buffer + Format('STARTING %d ', [FileStart]);
1870 FMetaData.Add(Buffer);
1871 end; //end_if
1872 qryDB.Next;
1873 end;
1874 qryDB.Close;
1875
1876 qryDB.SQL.Text := LogsSQL;
1877 qryDB.ExecQuery;
1878 while not qryDB.Eof do
1879 begin
1880
1881 if qryDB.FieldByName('RDB$FILE_FLAGS').IsNull then
1882 FileFlags := 0
1883 else
1884 FileFlags := qryDB.FieldByName('RDB$FILE_FLAGS').AsInteger;
1885 if qryDB.FieldByName('RDB$FILE_LENGTH').IsNull then
1886 FileLength := 0
1887 else
1888 FileLength := qryDB.FieldByName('RDB$FILE_LENGTH').AsInteger;
1889
1890 Buffer := '';
1891 HasWal := true;
1892 if First then
1893 begin
1894 if NoDB then
1895 Buffer := '/* ';
1896 Buffer := Buffer + LineEnding + 'ALTER DATABASE ADD ';
1897 First := false;
1898 end; //end_if
1899 if FirstFile then
1900 Buffer := Buffer + 'LOGFILE ';
1901 { Overflow files also have the serial bit set }
1902 if (FileFlags and LOG_default) = 0 then
1903 begin
1904 if (FileFlags and LOG_overflow) <> 0 then
1905 Buffer := Buffer + Format(')%s OVERFLOW ''%s''',
1906 [LineEnding, qryDB.FieldByName('RDB$FILE_NAME').AsString])
1907 else
1908 if (FileFlags and LOG_serial) <> 0 then
1909 Buffer := Buffer + Format('%s BASE_NAME ''%s''',
1910 [LineEnding, qryDB.FieldByName('RDB$FILE_NAME').AsString])
1911 { Since we are fetching order by FILE_FLAGS, the LOG_0verflow will
1912 be last. It will only appear if there were named round robin,
1913 so we must close the parens first }
1914
1915 { We have round robin and overflow file specifications }
1916 else
1917 begin
1918 if FirstFile then
1919 Buffer := Buffer + '('
1920 else
1921 Buffer := Buffer + Format(',%s ', [LineEnding]);
1922 FirstFile := false;
1923
1924 Buffer := Buffer + Format('''%s''', [qryDB.FieldByName('RDB$FILE_NAME').AsString]);
1925 end; //end_else
1926 end;
1927 { Any file can have a length }
1928 if FileLength <> 0 then
1929 Buffer := Buffer + Format(' SIZE %d ', [FileLength]);
1930 FMetaData.Add(Buffer);
1931 qryDB.Next;
1932 end;
1933 qryDB.Close;
1934 Buffer := '';
1935 if HasWal then
1936 begin
1937 Buffer := Buffer + PrintSet(SetUsed);
1938 Buffer := Buffer + Format('NUM_LOG_BUFFERS = %d',
1939 [GetLongDatabaseInfo(isc_info_num_wal_buffers)]);
1940 Buffer := Buffer + PrintSet(SetUsed);
1941 Buffer := Buffer + Format('LOG_BUFFER_SIZE = %d',
1942 [GetLongDatabaseInfo(isc_info_wal_buffer_size)]);
1943 Buffer := Buffer + PrintSet(SetUsed);
1944 Buffer := Buffer + Format('GROUP_COMMIT_WAIT_TIME = %d',
1945 [GetLongDatabaseInfo(isc_info_wal_grpc_wait_usecs)]);
1946 Buffer := Buffer + PrintSet(SetUsed);
1947 Buffer := Buffer + Format('CHECK_POINT_LENGTH = %d',
1948 [GetLongDatabaseInfo(isc_info_wal_ckpt_length)]);
1949 FMetaData.Add(Buffer);
1950
1951 end;
1952 if not First then
1953 begin
1954 if NoDB then
1955 FMetaData.Add(Format('%s */%s', [LineEnding, LineEnding]))
1956 else
1957 FMetaData.Add(Format('%s%s%s', [Term, LineEnding, LineEnding]));
1958 end;
1959 finally
1960 qryDB.Free;
1961 end;
1962
1963 (*
1964 *)
1965 end;
1966
1967 { ListDomainTable
1968 Functional description
1969 List domains as identified by fields with any constraints on them
1970 for the named table
1971
1972 Parameters: table_name == only extract domains for this table }
1973
1974 procedure TIBExtract.ListDomains(ObjectName: String; ExtractType : TExtractType);
1975 const
1976 DomainSQL =
1977 'SELECT distinct fld.* FROM RDB$FIELDS FLD JOIN RDB$RELATION_FIELDS RFR ON ' +
1978 ' RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME ' +
1979 'WHERE RFR.RDB$RELATION_NAME = :TABLE_NAME ' +
1980 'ORDER BY FLD.RDB$FIELD_NAME';
1981
1982 DomainByNameSQL =
1983 'SELECT * FROM RDB$FIELDS FLD ' +
1984 'WHERE FLD.RDB$FIELD_NAME = :DomainName ' +
1985 'ORDER BY FLD.RDB$FIELD_NAME';
1986
1987 AllDomainSQL =
1988 'select * from RDB$FIELDS ' +
1989 'where RDB$SYSTEM_FLAG <> 1 ' +
1990 'order BY RDB$FIELD_NAME';
1991
1992 var
1993 First : Boolean;
1994 qryDomains : TIBSQL;
1995 FieldName, Line : String;
1996
1997 function FormatDomainStr : String;
1998 var
1999 i, SubType : Integer;
2000 PrecisionKnown : Boolean;
2001 begin
2002 Result := '';
2003 for i := Low(ColumnTypes) to High(ColumnTypes) do
2004 if qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = ColumnTypes[i].SQLType then
2005 begin
2006 PrecisionKnown := FALSE;
2007 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
2008 begin
2009 if qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_short, blr_long, blr_int64] then
2010 begin
2011 { We are ODS >= 10 and could be any Dialect }
2012 if (FDatabaseInfo.DBSQLDialect >= 3) and
2013 (not qryDomains.FieldByName('RDB$FIELD_PRECISION').IsNull) and
2014 (qryDomains.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger > 0) and
2015 (qryDomains.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger <= MAX_INTSUBTYPES) then
2016 begin
2017 Result := Result + Format('%s(%d, %d)', [
2018 IntegralSubtypes [qryDomains.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger],
2019 qryDomains.FieldByName('RDB$FIELD_PRECISION').AsInteger,
2020 -1 * qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger]);
2021 PrecisionKnown := true;
2022 end;
2023 end;
2024 end;
2025 if PrecisionKnown = false then
2026 begin
2027 { Take a stab at numerics and decimals }
2028 if (qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_short) and
2029 (qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then
2030 Result := Result + Format('NUMERIC(4, %d)',
2031 [-qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger] )
2032 else
2033 if (qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_long) and
2034 (qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then
2035 Result := Result + Format('NUMERIC(9, %d)',
2036 [-qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger] )
2037 else
2038 if (qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_double) and
2039 (qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then
2040 Result := Result + Format('NUMERIC(15, %d)',
2041 [-qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger] )
2042 else
2043 Result := Result + ColumnTypes[i].TypeName;
2044 end;
2045 break;
2046 end;
2047
2048 if qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_blob then
2049 begin
2050 subtype := qryDomains.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger;
2051 Result := Result + ' SUB_TYPE ';
2052 if (subtype > 0) and (subtype <= MAXSUBTYPES) then
2053 Result := Result + SubTypes[subtype]
2054 else
2055 Result := Result + Format('%d', [subtype]);
2056 Result := Result + Format(' SEGMENT SIZE %d', [qryDomains.FieldByName('RDB$SEGMENT_LENGTH').AsInteger]);
2057 end //end_if
2058 else
2059 if (qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_text, blr_varying]) then
2060 begin
2061 if not qryDomains.FieldByName('RDB$CHARACTER_LENGTH').IsNull then
2062 Result := Result + Format('(%d)', [qryDomains.FieldByName('RDB$CHARACTER_LENGTH').AsInteger])
2063 else
2064 Result := Result + Format('(%d)', [qryDomains.FieldByName('RDB$FIELD_LENGTH').AsInteger]);
2065 end;
2066
2067 { since the character set is part of the field type, display that
2068 information now. }
2069 if not qryDomains.FieldByName('RDB$CHARACTER_SET_ID').IsNull then
2070 Result := Result + GetCharacterSets(qryDomains.FieldByName('RDB$CHARACTER_SET_ID').AsInteger,
2071 0, FALSE);
2072 if not qryDomains.FieldByName('RDB$DIMENSIONS').IsNull then
2073 Result := GetArrayField(qryDomains.FieldByName('RDB$FIELD_SOURCE').AsString);
2074
2075 if not qryDomains.FieldByName('RDB$DEFAULT_SOURCE').IsNull then
2076 Result := Result + Format('%s%s %s', [LineEnding, TAB,
2077 qryDomains.FieldByName('RDB$DEFAULT_SOURCE').AsString]);
2078
2079 if not qryDomains.FieldByName('RDB$VALIDATION_SOURCE').IsNull then
2080 if Pos('CHECK', AnsiUpperCase(qryDomains.FieldByName('RDB$VALIDATION_SOURCE').AsString)) = 1 then
2081 Result := Result + Format('%s%s %s', [LineEnding, TAB,
2082 qryDomains.FieldByName('RDB$VALIDATION_SOURCE').AsString])
2083 else
2084 Result := Result + Format('%s%s /* %s */', [LineEnding, TAB,
2085 qryDomains.FieldByName('RDB$VALIDATION_SOURCE').AsString]);
2086
2087 if qryDomains.FieldByName('RDB$NULL_FLAG').AsInteger = 1 then
2088 Result := Result + ' NOT NULL';
2089
2090 { Show the collation order if one has been specified. If the collation
2091 order is the default for the character set being used, then no collation
2092 order will be shown ( because it isn't needed ).
2093
2094 If the collation id is 0, then the default for the character set is
2095 being used so there is no need to retrieve the collation information.}
2096
2097 if (not qryDomains.FieldByName('RDB$COLLATION_ID').IsNull) and
2098 (qryDomains.FieldByName('RDB$COLLATION_ID').AsInteger <> 0) then
2099 Result := Result + GetCharacterSets(qryDomains.FieldByName('RDB$CHARACTER_SET_ID').AsInteger,
2100 qryDomains.FieldByName('RDB$COLLATION_ID').AsInteger, true);
2101 end;
2102
2103 begin
2104 First := true;
2105 qryDomains := TIBSQL.Create(FDatabase);
2106 try
2107 if ObjectName <> '' then
2108 begin
2109 if ExtractType = etTable then
2110 begin
2111 qryDomains.SQL.Text := DomainSQL;
2112 qryDomains.Params.ByName('table_name').AsString := ObjectName;
2113 end
2114 else
2115 begin
2116 qryDomains.SQL.Text := DomainByNameSQL;
2117 qryDomains.Params.ByName('DomainName').AsString := ObjectName;
2118 end;
2119 end
2120 else
2121 qryDomains.SQL.Text := AllDomainSQL;
2122
2123 qryDomains.ExecQuery;
2124 while not qryDomains.Eof do
2125 begin
2126 FieldName := qryDomains.FieldByName('RDB$FIELD_NAME').AsString;
2127 { Skip over artifical domains }
2128 if (Pos('RDB$',FieldName) = 1) and
2129 (FieldName[5] in ['0'..'9']) and
2130 (qryDomains.FieldByName('RDB$SYSTEM_FLAG').AsInteger <> 1) then
2131 begin
2132 qryDomains.Next;
2133 continue;
2134 end;
2135
2136 if First then
2137 begin
2138 FMetaData.Add('/* Domain definitions */');
2139 First := false;
2140 end;
2141
2142 Line := Format('CREATE DOMAIN %s AS ', [FieldName]);
2143 Line := Line + FormatDomainStr + Term;
2144 FMetaData.Add(Line);
2145 qryDomains.Next;
2146 end;
2147 finally
2148 qryDomains.Free;
2149 end;
2150 end;
2151
2152 { ListException
2153 Functional description
2154 List all exceptions defined in the database
2155
2156 Parameters: none }
2157
2158 procedure TIBExtract.ListException(ExceptionName : String = '');
2159 const
2160 ExceptionSQL =
2161 'select * from RDB$EXCEPTIONS ' +
2162 'ORDER BY RDB$EXCEPTION_NAME';
2163
2164 ExceptionNameSQL =
2165 'select * from RDB$EXCEPTIONS ' +
2166 'WHERE RDB$EXCEPTION_NAME = :ExceptionName ' +
2167 'ORDER BY RDB$EXCEPTION_NAME';
2168
2169 var
2170 First : Boolean;
2171 qryException : TIBSQL;
2172 begin
2173 First := true;
2174 qryException := TIBSQL.Create(FDatabase);
2175 try
2176 if ExceptionName = '' then
2177 qryException.SQL.Text := ExceptionSQL
2178 else
2179 begin
2180 qryException.SQL.Text := ExceptionNameSQL;
2181 qryException.Params.ByName('ExceptionName').AsString := ExceptionName;
2182 end;
2183
2184 qryException.ExecQuery;
2185 while not qryException.Eof do
2186 begin
2187 if First then
2188 begin
2189 FMetaData.Add('');
2190 FMetaData.Add('/* Exceptions */');
2191 FMetaData.Add('');
2192 First := false;
2193 end; //end_if
2194
2195 FMetaData.Add(Format('CREATE EXCEPTION %s %s%s',
2196 [QuoteIdentifier( qryException.FieldByName('RDB$EXCEPTION_NAME').AsString),
2197 QuotedStr(qryException.FieldByName('RDB$MESSAGE').AsString), Term]));
2198 qryException.Next;
2199 end;
2200 finally
2201 qryException.Free;
2202 end;
2203 end;
2204
2205 { ListFilters
2206
2207 Functional description
2208 List all blob filters
2209
2210 Parameters: none
2211 Results in
2212 DECLARE FILTER <fname> INPUT_TYPE <blob_sub_type> OUTPUT_TYPE <blob_subtype>
2213 ENTRY_POINT <string> MODULE_NAME <string> }
2214
2215 procedure TIBExtract.ListFilters(FilterName : String = '');
2216 const
2217 FiltersSQL =
2218 'SELECT * FROM RDB$FILTERS ' +
2219 'ORDER BY RDB$FUNCTION_NAME';
2220 FilterNameSQL =
2221 'SELECT * FROM RDB$FILTERS ' +
2222 'WHERE RDB$FUNCTION_NAME = :FunctionName ' +
2223 'ORDER BY RDB$FUNCTION_NAME';
2224
2225 var
2226 First : Boolean;
2227 qryFilters : TIBSQL;
2228 begin
2229 First := true;
2230 qryFilters := TIBSQL.Create(FDatabase);
2231 try
2232 if FilterName = '' then
2233 qryFilters.SQL.Text := FiltersSQL
2234 else
2235 begin
2236 qryFilters.SQL.Text := FilterNameSQL;
2237 qryFilters.Params.ByName('FunctionName').AsString := FilterName;
2238 end;
2239 qryFilters.ExecQuery;
2240 while not qryFilters.Eof do
2241 begin
2242 if First then
2243 begin
2244 FMetaData.Add('');
2245 FMetaData.Add('/* BLOB Filter declarations */');
2246 FMetaData.Add('');
2247 First := false;
2248 end; //end_if
2249
2250 FMetaData.Add(Format('DECLARE FILTER %s INPUT_TYPE %d OUTPUT_TYPE %d',
2251 [qryFilters.FieldByName('RDB$FUNCTION_NAME').AsString,
2252 qryFilters.FieldByName('RDB$INPUT_SUB_TYPE').AsInteger,
2253 qryFilters.FieldByName('RDB$OUTPUT_SUB_TYPE').AsInteger]));
2254 FMetaData.Add(Format('%sENTRY_POINT ''%s'' MODULE_NAME ''%s''%s%',
2255 [TAB, qryFilters.FieldByName('RDB$ENTRYPOINT').AsString,
2256 qryFilters.FieldByName('RDB$MODULE_NAME').AsString, Term]));
2257 FMetaData.Add('');
2258
2259 qryFilters.Next;
2260 end;
2261
2262 finally
2263 qryFilters.Free;
2264 end;
2265 end;
2266
2267 { ListForeign
2268 Functional description
2269 List all foreign key constraints and alter the tables }
2270
2271 procedure TIBExtract.ListForeign(ObjectName : String; ExtractType : TExtractType);
2272 const
2273 { Static queries for obtaining foreign constraints, where RELC1 is the
2274 foreign key constraints, RELC2 is the primary key lookup and REFC
2275 is the join table }
2276 ForeignSQL =
2277 'SELECT REFC.RDB$UPDATE_RULE REFC_UPDATE_RULE, REFC.RDB$DELETE_RULE REFC_DELETE_RULE, ' +
2278 ' RELC1.RDB$RELATION_NAME RELC1_RELATION_NAME, RELC2.RDB$RELATION_NAME RELC2_RELATION_NAME, ' +
2279 ' RELC1.RDB$INDEX_NAME RELC1_INDEX_NAME, RELC1.RDB$CONSTRAINT_NAME RELC1_CONSTRAINT_NAME, ' +
2280 ' RELC2.RDB$INDEX_NAME RELC2_INDEX_NAME ' +
2281 'FROM RDB$REF_CONSTRAINTS REFC, RDB$RELATION_CONSTRAINTS RELC1, ' +
2282 ' RDB$RELATION_CONSTRAINTS RELC2 ' +
2283 'WHERE ' +
2284 ' RELC1.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' AND ' +
2285 ' REFC.RDB$CONST_NAME_UQ = RELC2.RDB$CONSTRAINT_NAME AND ' +
2286 ' REFC.RDB$CONSTRAINT_NAME = RELC1.RDB$CONSTRAINT_NAME AND ' +
2287 ' (RELC2.RDB$CONSTRAINT_TYPE = ''UNIQUE'' OR ' +
2288 ' RELC2.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'') ' +
2289 'ORDER BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME';
2290
2291 ForeignNameSQL =
2292 'SELECT REFC.RDB$UPDATE_RULE REFC_UPDATE_RULE, REFC.RDB$DELETE_RULE REFC_DELETE_RULE, ' +
2293 ' RELC1.RDB$RELATION_NAME RELC1_RELATION_NAME, RELC2.RDB$RELATION_NAME RELC2_RELATION_NAME, ' +
2294 ' RELC1.RDB$INDEX_NAME RELC1_INDEX_NAME, RELC1.RDB$CONSTRAINT_NAME RELC1_CONSTRAINT_NAME, ' +
2295 ' RELC2.RDB$INDEX_NAME RELC2_INDEX_NAME ' +
2296 'FROM RDB$REF_CONSTRAINTS REFC, RDB$RELATION_CONSTRAINTS RELC1, ' +
2297 ' RDB$RELATION_CONSTRAINTS RELC2 ' +
2298 'WHERE ' +
2299 ' RELC1.RDB$RELATION_NAME = :TableName AND ' +
2300 ' RELC1.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' AND ' +
2301 ' REFC.RDB$CONST_NAME_UQ = RELC2.RDB$CONSTRAINT_NAME AND ' +
2302 ' REFC.RDB$CONSTRAINT_NAME = RELC1.RDB$CONSTRAINT_NAME AND ' +
2303 ' (RELC2.RDB$CONSTRAINT_TYPE = ''UNIQUE'' OR ' +
2304 ' RELC2.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'') ' +
2305 'ORDER BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME';
2306
2307 ForeignByNameSQL =
2308 'SELECT REFC.RDB$UPDATE_RULE REFC_UPDATE_RULE, REFC.RDB$DELETE_RULE REFC_DELETE_RULE, ' +
2309 ' RELC1.RDB$RELATION_NAME RELC1_RELATION_NAME, RELC2.RDB$RELATION_NAME RELC2_RELATION_NAME, ' +
2310 ' RELC1.RDB$INDEX_NAME RELC1_INDEX_NAME, RELC1.RDB$CONSTRAINT_NAME RELC1_CONSTRAINT_NAME, ' +
2311 ' RELC2.RDB$INDEX_NAME RELC2_INDEX_NAME ' +
2312 'FROM RDB$REF_CONSTRAINTS REFC, RDB$RELATION_CONSTRAINTS RELC1, ' +
2313 ' RDB$RELATION_CONSTRAINTS RELC2 ' +
2314 'WHERE ' +
2315 ' RELC1.RDB$CONSTRAINT_NAME = :ConstraintName AND ' +
2316 ' RELC1.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' AND ' +
2317 ' REFC.RDB$CONST_NAME_UQ = RELC2.RDB$CONSTRAINT_NAME AND ' +
2318 ' REFC.RDB$CONSTRAINT_NAME = RELC1.RDB$CONSTRAINT_NAME AND ' +
2319 ' (RELC2.RDB$CONSTRAINT_TYPE = ''UNIQUE'' OR ' +
2320 ' RELC2.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'') ' +
2321 'ORDER BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME';
2322
2323 var
2324 qryForeign : TIBSQL;
2325 Line : String;
2326
2327 begin
2328 qryForeign := TIBSQL.Create(FDatabase);
2329 try
2330 if ObjectName = '' then
2331 qryForeign.SQL.Text := ForeignSQL
2332 else
2333 begin
2334 if ExtractType = etTable then
2335 begin
2336 qryForeign.SQL.Text := ForeignNameSQL;
2337 qryForeign.Params.ByName('TableName').AsString := ObjectName;
2338 end
2339 else
2340 begin
2341 qryForeign.SQL.Text := ForeignByNameSQL;
2342 qryForeign.Params.ByName('ConstraintName').AsString := ObjectName;
2343 end;
2344 end;
2345 qryForeign.ExecQuery;
2346 while not qryForeign.Eof do
2347 begin
2348 Line := Format('ALTER TABLE %s ADD ', [QuoteIdentifier(
2349 qryForeign.FieldByName('RELC1_RELATION_NAME').AsString)]);
2350
2351 { If the name of the constraint is not INTEG..., print it.
2352 INTEG... are internally generated names. }
2353 if (not qryForeign.FieldByName('RELC1_CONSTRAINT_NAME').IsNull) and
2354 ( Pos('INTEG', qryForeign.FieldByName('RELC1_CONSTRAINT_NAME').AsString) <> 1) then
2355 Line := Line + Format('CONSTRAINT %s ', [QuoteIdentifier(
2356 Trim(qryForeign.FieldByName('RELC1_CONSTRAINT_NAME').AsString))]);
2357
2358 Line := Line + Format('FOREIGN KEY (%s) REFERENCES %s ', [
2359 GetIndexSegments(qryForeign.FieldByName('RELC1_INDEX_NAME').AsString),
2360 Trim(qryForeign.FieldByName('RELC2_RELATION_NAME').AsString)]);
2361
2362 Line := Line + Format('(%s)',
2363 [GetIndexSegments(qryForeign.FieldByName('RELC2_INDEX_NAME').AsString)]);
2364
2365 { Add the referential actions, if any }
2366 if (not qryForeign.FieldByName('REFC_UPDATE_RULE').IsNull) and
2367 (Trim(qryForeign.FieldByName('REFC_UPDATE_RULE').AsString) <> 'RESTRICT') then
2368 Line := Line + Format(' ON UPDATE %s',
2369 [Trim(qryForeign.FieldByName('REFC_UPDATE_RULE').AsString)]);
2370
2371 if (not qryForeign.FieldByName('REFC_DELETE_RULE').IsNull) and
2372 (Trim(qryForeign.FieldByName('REFC_DELETE_RULE').AsString) <> 'RESTRICT') then
2373 Line := Line + Format(' ON DELETE %s',
2374 [Trim(qryForeign.FieldByName('REFC_DELETE_RULE').AsString)]);
2375
2376 Line := Line + Term;
2377 FMetaData.Add(Line);
2378 qryForeign.Next;
2379 end;
2380 finally
2381 qryForeign.Free;
2382 end;
2383 end;
2384
2385 { ListFunctions
2386
2387 Functional description
2388 List all external functions
2389
2390 Parameters: none
2391 Results in
2392 DECLARE EXTERNAL FUNCTION function_name
2393 CHAR [256] , INTEGER, ....
2394 RETURNS INTEGER BY VALUE
2395 ENTRY_POINT entrypoint MODULE_NAME module; }
2396
2397 procedure TIBExtract.ListFunctions(FunctionName : String = '');
2398 const
2399 FunctionSQL =
2400 'SELECT * FROM RDB$FUNCTIONS WHERE RDB$SYSTEM_FLAG = 0 ' +
2401 'ORDER BY RDB$FUNCTION_NAME';
2402
2403 FunctionNameSQL =
2404 'SELECT * FROM RDB$FUNCTIONS ' +
2405 'WHERE RDB$FUNCTION_NAME = :FunctionName ' +
2406 'ORDER BY RDB$FUNCTION_NAME';
2407
2408 FunctionArgsSQL =
2409 'SELECT * FROM RDB$FUNCTION_ARGUMENTS ' +
2410 'WHERE ' +
2411 ' :FUNCTION_NAME = RDB$FUNCTION_NAME ' +
2412 'ORDER BY RDB$ARGUMENT_POSITION';
2413
2414 FuncArgsPosSQL =
2415 'SELECT * FROM RDB$FUNCTION_ARGUMENTS ' +
2416 'WHERE ' +
2417 ' RDB$FUNCTION_NAME = :RDB$FUNCTION_NAME AND ' +
2418 ' RDB$ARGUMENT_POSITION = :RDB$ARGUMENT_POSITION';
2419
2420 CharSetSQL =
2421 'SELECT * FROM RDB$CHARACTER_SETS ' +
2422 'WHERE ' +
2423 ' RDB$CHARACTER_SET_ID = :CHARACTER_SET_ID';
2424
2425 var
2426 qryFunctions, qryFuncArgs, qryCharSets, qryFuncPos : TIBSQL;
2427 First, FirstArg, DidCharset, PrecisionKnown : Boolean;
2428 ReturnBuffer, TypeBuffer, Line : String;
2429 i, FieldType : Integer;
2430 begin
2431 First := true;
2432 qryFunctions := TIBSQL.Create(FDatabase);
2433 qryFuncArgs := TIBSQL.Create(FDatabase);
2434 qryFuncPos := TIBSQL.Create(FDatabase);
2435 qryCharSets := TIBSQL.Create(FDatabase);
2436 try
2437 if FunctionName = '' then
2438 qryFunctions.SQL.Text := FunctionSQL
2439 else
2440 begin
2441 qryFunctions.SQL.Text := FunctionNameSQL;
2442 qryFunctions.Params.ByName('FunctionName').AsString := FunctionName;
2443 end;
2444 qryFuncArgs.SQL.Text := FunctionArgsSQL;
2445 qryFuncPos.SQL.Text := FuncArgsPosSQL;
2446 qryCharSets.SQL.Text := CharSetSQL;
2447 qryFunctions.ExecQuery;
2448 while not qryFunctions.Eof do
2449 begin
2450 if First then
2451 begin
2452 FMEtaData.Add(Format('%s/* External Function declarations */%s',
2453 [LineEnding, LineEnding]));
2454 First := false;
2455 end; //end_if
2456 { Start new function declaration }
2457 FMetaData.Add(Format('DECLARE EXTERNAL FUNCTION %s',
2458 [qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString]));
2459 Line := '';
2460
2461 FirstArg := true;
2462 qryFuncArgs.Params.ByName('FUNCTION_NAME').AsString :=
2463 qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString;
2464
2465 qryFuncArgs.ExecQuery;
2466 while not qryFuncArgs.Eof do
2467 begin
2468 { Find parameter type }
2469 i := 0;
2470 FieldType := qryFuncArgs.FieldByName('RDB$FIELD_TYPE').AsInteger;
2471 while FieldType <> ColumnTypes[i].SQLType do
2472 Inc(i);
2473
2474 { Print length where appropriate }
2475 if FieldType in [ blr_text, blr_varying, blr_cstring] then
2476 begin
2477 DidCharset := false;
2478
2479 qryCharSets.Params.ByName('CHARACTER_SET_ID').AsString :=
2480 qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID').AsString;
2481 qryCharSets.ExecQuery;
2482 while not qryCharSets.Eof do
2483 begin
2484 DidCharset := true;
2485 TypeBuffer := Format('%s(%d) CHARACTER SET %s',
2486 [ColumnTypes[i].TypeName,
2487 qryFuncArgs.FieldByName('RDB$FIELD_LENGTH').AsInteger div
2488 Max(1,qryCharSets.FieldByName('RDB$BYTES_PER_CHARACTER').AsInteger),
2489 qryCharSets.FieldByName('RDB$CHARACTER_SET_NAME').AsString]);
2490 qryCharSets.Next;
2491 end;
2492 qryCharSets.Close;
2493 if not DidCharset then
2494 TypeBuffer := Format('%s(%d)', [ColumnTypes[i].TypeName,
2495 qryFuncArgs.FieldByName('RDB$FIELD_LENGTH').AsInteger]);
2496 end //end_if
2497 else
2498 begin
2499 PrecisionKnown := false;
2500 if (FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10) and
2501 (FieldType in [blr_short, blr_long, blr_int64]) then
2502 begin
2503 qryFuncPos.Params.ByName('RDB$FUNCTION_NAME').AsString :=
2504 qryFuncArgs.FieldByName('RDB$FUNCTION_NAME').AsString;
2505 qryFuncPos.Params.ByName('RDB$ARGUMENT_POSITION').AsInteger :=
2506 qryFuncArgs.FieldByName('RDB$ARGUMENT_POSITION').AsInteger;
2507
2508 qryFuncPos.ExecQuery;
2509 while not qryFuncPos.Eof do
2510 begin
2511 { We are ODS >= 10 and could be any Dialect }
2512 if not qryFuncPos.FieldByName('RDB$FIELD_PRECISION').IsNull then
2513 begin
2514 { We are Dialect >=3 since FIELD_PRECISION is non-NULL }
2515 if (qryFuncPos.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger > 0) and
2516 (qryFuncPos.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger <= MAX_INTSUBTYPES) then
2517 begin
2518 TypeBuffer := Format('%s(%d, %d)',
2519 [IntegralSubtypes[qryFuncPos.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger],
2520 qryFuncPos.FieldByName('RDB$FIELD_PRECISION').AsInteger,
2521 -qryFuncPos.FieldByName('RDB$FIELD_SCALE').AsInteger] );
2522 PrecisionKnown := true;
2523 end; //end_if
2524 end; { if field_precision is not null }
2525 qryFuncPos.Next;
2526 end;
2527 qryFuncPos.Close;
2528 end; { if major_ods >= ods_version10 && }
2529 if not PrecisionKnown then
2530 begin
2531 { Take a stab at numerics and decimals }
2532 if (FieldType = blr_short) and
2533 (qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then
2534 TypeBuffer := Format('NUMERIC(4, %d)',
2535 [-qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger])
2536 else
2537 if (FieldType = blr_long) and
2538 (qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then
2539 TypeBuffer := Format('NUMERIC(9, %d)',
2540 [-qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger])
2541 else
2542 if (FieldType = blr_double) and
2543 (qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then
2544 TypeBuffer := Format('NUMERIC(15, %d)',
2545 [-qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger])
2546 else
2547 TypeBuffer := ColumnTypes[i].TypeName;
2548 end; { if not PrecisionKnown }
2549 end; { if FCHAR or VARCHAR or CSTRING ... else }
2550
2551 if qryFunctions.FieldByName('RDB$RETURN_ARGUMENT').AsInteger =
2552 qryFuncArgs.FieldByName('RDB$ARGUMENT_POSITION').AsInteger then
2553 begin
2554 ReturnBuffer := 'RETURNS ' + TypeBuffer;
2555 if qryFuncArgs.FieldByName('RDB$MECHANISM').AsInteger = 0 then
2556 ReturnBuffer := ReturnBuffer + ' BY VALUE ';
2557 if qryFuncArgs.FieldByName('RDB$MECHANISM').AsInteger < 0 then
2558 ReturnBuffer := ReturnBuffer + ' FREE_IT';
2559 end
2560 else
2561 begin
2562 { First arg needs no comma }
2563 if FirstArg then
2564 begin
2565 Line := Line + TypeBuffer;
2566 FirstArg := false;
2567 end
2568 else
2569 Line := Line + ', ' + TypeBuffer;
2570 end; //end_else
2571 qryFuncArgs.Next;
2572 end;
2573 qryFuncArgs.Close;
2574
2575 FMetaData.Add(Line);
2576 FMetaData.Add(ReturnBuffer);
2577 FMetaData.Add(Format('ENTRY_POINT ''%s'' MODULE_NAME ''%s''%s%s%s',
2578 [qryFunctions.FieldByName('RDB$ENTRYPOINT').AsString,
2579 qryFunctions.FieldByName('RDB$MODULE_NAME').AsString,
2580 Term, LineEnding, LineEnding]));
2581
2582 qryFunctions.Next;
2583 end;
2584 finally
2585 qryFunctions.Free;
2586 qryFuncArgs.Free;
2587 qryCharSets.Free;
2588 qryFuncPos.Free;
2589 end;
2590 end;
2591
2592 { ListGenerators
2593 Functional description
2594 Re create all non-system generators }
2595
2596 procedure TIBExtract.ListGenerators(GeneratorName: String;
2597 ExtractTypes: TExtractTypes);
2598 const
2599 GeneratorSQL =
2600 'SELECT RDB$GENERATOR_NAME ' +
2601 'FROM RDB$GENERATORS ' +
2602 'WHERE ' +
2603 ' (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG <> 1) ' +
2604 'ORDER BY RDB$GENERATOR_NAME';
2605
2606 GeneratorNameSQL =
2607 'SELECT RDB$GENERATOR_NAME ' +
2608 'FROM RDB$GENERATORS ' +
2609 'WHERE RDB$GENERATOR_NAME = :GeneratorName AND ' +
2610 ' (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG <> 1) ' +
2611 'ORDER BY RDB$GENERATOR_NAME';
2612
2613 GeneratorValueSQL =
2614 'SELECT GEN_ID(%s,0) as GENERATORVALUE From RDB$Database';
2615
2616 var
2617 qryGenerator : TIBSQL;
2618 qryValue: TIBSQL;
2619 GenName : String;
2620 begin
2621 qryGenerator := TIBSQL.Create(FDatabase);
2622 qryValue := TIBSQL.Create(FDatabase);
2623 try
2624 if GeneratorName = '' then
2625 qryGenerator.SQL.Text := GeneratorSQL
2626 else
2627 begin
2628 qryGenerator.SQL.Text := GeneratorNameSQL;
2629 qryGenerator.Params.ByName('GeneratorName').AsString := GeneratorName;
2630 end;
2631 qryGenerator.ExecQuery;
2632 FMetaData.Add('');
2633 while not qryGenerator.Eof do
2634 begin
2635 GenName := qryGenerator.FieldByName('RDB$GENERATOR_NAME').AsString;
2636 if ((Pos('RDB$',GenName) = 1) and
2637 (GenName[5] in ['0'..'9'])) or
2638 ((Pos('SQL$',GenName) = 1) and
2639 (GenName[5] in ['0'..'9'])) then
2640 begin
2641 qryGenerator.Next;
2642 continue;
2643 end;
2644 FMetaData.Add(Format('CREATE SEQUENCE %s%s',
2645 [QuoteIdentifier( GenName),
2646 Term]));
2647 if etData in ExtractTypes then
2648 begin
2649 qryValue.SQL.Text := Format(GeneratorValueSQL,[GenName]);
2650 qryValue.ExecQuery;
2651 try
2652 if not qryValue.EOF then
2653 FMetaData.Add(Format('ALTER SEQUENCE %s RESTART WITH %d;',
2654 [QuoteIdentifier( GenName),
2655 qryValue.FieldByName('GENERATORVALUE').AsInt64]));
2656 finally
2657 qryValue.Close;
2658 end;
2659 end;
2660 qryGenerator.Next;
2661 end;
2662 finally
2663 qryGenerator.Free;
2664 qryValue.Free;
2665 end;
2666 end;
2667
2668 { ListIndex
2669 Functional description
2670 Define all non-constraint indices
2671 Use a static SQL query to get the info and print it.
2672
2673 Uses get_index_segment to provide a key list for each index }
2674
2675 procedure TIBExtract.ListIndex(ObjectName : String; ExtractType : TExtractType);
2676 const
2677 IndexSQL =
2678 'SELECT IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, IDX.RDB$UNIQUE_FLAG, ' +
2679 ' IDX.RDB$INDEX_TYPE ' +
2680 'FROM RDB$INDICES IDX JOIN RDB$RELATIONS RELC ON ' +
2681 ' IDX.RDB$RELATION_NAME = RELC.RDB$RELATION_NAME ' +
2682 'WHERE (RELC.RDB$SYSTEM_FLAG <> 1 OR RELC.RDB$SYSTEM_FLAG IS NULL) AND ' +
2683 ' NOT EXISTS (SELECT * FROM RDB$RELATION_CONSTRAINTS RC ' +
2684 ' WHERE RC.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME) ' +
2685 'ORDER BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME';
2686
2687 IndexNameSQL =
2688 'SELECT IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, IDX.RDB$UNIQUE_FLAG, ' +
2689 ' IDX.RDB$INDEX_TYPE ' +
2690 'FROM RDB$INDICES IDX JOIN RDB$RELATIONS RELC ON ' +
2691 ' IDX.RDB$RELATION_NAME = RELC.RDB$RELATION_NAME ' +
2692 'WHERE (RELC.RDB$SYSTEM_FLAG <> 1 OR RELC.RDB$SYSTEM_FLAG IS NULL) AND ' +
2693 ' RELC.RDB$RELATION_NAME = :RelationName AND ' +
2694 ' NOT EXISTS (SELECT * FROM RDB$RELATION_CONSTRAINTS RC ' +
2695 ' WHERE RC.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME) ' +
2696 'ORDER BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME';
2697
2698 IndexByNameSQL =
2699 'SELECT IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, IDX.RDB$UNIQUE_FLAG, ' +
2700 ' IDX.RDB$INDEX_TYPE ' +
2701 'FROM RDB$INDICES IDX JOIN RDB$RELATIONS RELC ON ' +
2702 ' IDX.RDB$RELATION_NAME = RELC.RDB$RELATION_NAME ' +
2703 'WHERE (RELC.RDB$SYSTEM_FLAG <> 1 OR RELC.RDB$SYSTEM_FLAG IS NULL) AND ' +
2704 ' IDX.RDB$INDEX_NAME = :IndexName AND ' +
2705 ' NOT EXISTS (SELECT * FROM RDB$RELATION_CONSTRAINTS RC ' +
2706 ' WHERE RC.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME) ' +
2707 'ORDER BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME';
2708
2709 var
2710 qryIndex : TIBSQL;
2711 First : Boolean;
2712 Unique, IdxType, Line : String;
2713 begin
2714 First := true;
2715 qryIndex := TIBSQL.Create(FDatabase);
2716 try
2717 if ObjectName = '' then
2718 qryIndex.SQL.Text := IndexSQL
2719 else
2720 begin
2721 if ExtractType = etTable then
2722 begin
2723 qryIndex.SQL.Text := IndexNameSQL;
2724 qryIndex.Params.ByName('RelationName').AsString := ObjectName;
2725 end
2726 else
2727 begin
2728 qryIndex.SQL.Text := IndexByNameSQL;
2729 qryIndex.Params.ByName('IndexName').AsString := ObjectName;
2730 end;
2731 end;
2732 qryIndex.ExecQuery;
2733 while not qryIndex.Eof do
2734 begin
2735 if First then
2736 begin
2737 if ObjectName = '' then
2738 FMetaData.Add(LineEnding + '/* Index definitions for all user tables */' + LineEnding)
2739 else
2740 FMetaData.Add(LineEnding + '/* Index definitions for ' + ObjectName + ' */' + LineEnding);
2741 First := false;
2742 end; //end_if
2743
2744 if qryIndex.FieldByName('RDB$UNIQUE_FLAG').AsInteger = 1 then
2745 Unique := ' UNIQUE'
2746 else
2747 Unique := '';
2748
2749 if qryIndex.FieldByName('RDB$INDEX_TYPE').AsInteger = 1 then
2750 IdxType := ' DESCENDING'
2751 else
2752 IdxType := '';
2753
2754 Line := Format('CREATE%s%s INDEX %s ON %s(', [Unique, IdxType,
2755 QuoteIdentifier(
2756 qryIndex.FieldByName('RDB$INDEX_NAME').AsString),
2757 QuoteIdentifier(
2758 qryIndex.FieldByName('RDB$RELATION_NAME').AsString)]);
2759
2760 Line := Line + GetIndexSegments(qryIndex.FieldByName('RDB$INDEX_NAME').AsString) +
2761 ')' + Term;
2762
2763 FMetaData.Add(Line);
2764 qryIndex.Next;
2765 end;
2766 finally
2767 qryIndex.Free;
2768 end;
2769 end;
2770
2771 { ListViews
2772 Functional description
2773 Show text of views.
2774 Use a SQL query to get the info and print it.
2775 Note: This should also contain check option }
2776
2777 procedure TIBExtract.ListViews(ViewName : String);
2778 const
2779 ViewSQL =
2780 'with recursive Views as ( ' +
2781 ' Select RDB$RELATION_NAME, 1 as ViewLevel from RDB$RELATIONS ' +
2782 ' Where RDB$RELATION_TYPE = 1 and RDB$SYSTEM_FLAG = 0 '+
2783 ' UNION ALL ' +
2784 ' Select D.RDB$DEPENDED_ON_NAME, ViewLevel + 1 From RDB$DEPENDENCIES D ' +
2785 ' JOIN Views on Views.RDB$RELATION_NAME = D.RDB$DEPENDENT_NAME ' +
2786 ' and Views.RDB$RELATION_NAME <> D.RDB$DEPENDED_ON_NAME ' +
2787 ' JOIN RDB$RELATIONS R On R.RDB$RELATION_NAME = D.RDB$DEPENDED_ON_NAME ' +
2788 ')' +
2789 'SELECT R.RDB$RELATION_NAME, R.RDB$OWNER_NAME, R.RDB$VIEW_SOURCE FROM RDB$RELATIONS R ' +
2790 'JOIN ( ' +
2791 'Select RDB$RELATION_NAME, max(ViewLevel) as ViewLevel From Views ' +
2792 'Group By RDB$RELATION_NAME) A On A.RDB$RELATION_NAME = R.RDB$RELATION_NAME ' +
2793 'Where R.RDB$RELATION_TYPE = 1 and R.RDB$SYSTEM_FLAG = 0 '+
2794 'Order by A.ViewLevel desc, R.RDB$RELATION_NAME asc';
2795
2796 {
2797 'SELECT RDB$RELATION_NAME, RDB$OWNER_NAME, RDB$VIEW_SOURCE ' +
2798 'FROM RDB$RELATIONS ' +
2799 'WHERE ' +
2800 ' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' +
2801 ' NOT RDB$VIEW_BLR IS NULL AND ' +
2802 ' RDB$FLAGS = 1 ' +
2803 'ORDER BY RDB$RELATION_ID'; }
2804
2805 ViewNameSQL =
2806 'SELECT RDB$RELATION_NAME, RDB$OWNER_NAME, RDB$VIEW_SOURCE ' +
2807 'FROM RDB$RELATIONS ' +
2808 'WHERE ' +
2809 ' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' +
2810 ' NOT RDB$VIEW_BLR IS NULL AND ' +
2811 ' RDB$FLAGS = 1 AND ' +
2812 ' RDB$RELATION_NAME = :ViewName ' +
2813 'ORDER BY RDB$RELATION_ID';
2814
2815 ColumnSQL =
2816 'SELECT RDB$FIELD_NAME FROM RDB$RELATION_FIELDS ' +
2817 'WHERE ' +
2818 ' RDB$RELATION_NAME = :RELATION_NAME ' +
2819 'ORDER BY RDB$FIELD_POSITION';
2820
2821 var
2822 qryView, qryColumns : TIBSQL;
2823 SList : TStrings;
2824 begin
2825 qryView := TIBSQL.Create(FDatabase);
2826 qryColumns := TIBSQL.Create(FDatabase);
2827 SList := TStringList.Create;
2828 try
2829 if ViewName = '' then
2830 qryView.SQL.Text := ViewSQL
2831 else
2832 begin
2833 qryView.SQL.Text := ViewNameSQL;
2834 qryView.Params.ByName('ViewName').AsString := ViewName;
2835 end;
2836 qryColumns.SQL.Text := ColumnSQL;
2837 qryView.ExecQuery;
2838 while not qryView.Eof do
2839 begin
2840 SList.Add(Format('%s/* View: %s, Owner: %s */%s',
2841 [LineEnding, qryView.FieldByName('RDB$RELATION_NAME').AsString,
2842 qryView.FieldByName('RDB$OWNER_NAME').AsString, LineEnding]));
2843
2844 SList.Add(Format('CREATE VIEW %s (', [QuoteIdentifier(
2845 qryView.FieldByName('RDB$RELATION_NAME').AsString)]));
2846
2847 qryColumns.Params.ByName('RELATION_NAME').AsString :=
2848 qryView.FieldByName('RDB$RELATION_NAME').AsString;
2849 qryColumns.ExecQuery;
2850 while not qryColumns.Eof do
2851 begin
2852 SList.Add(' ' + QuoteIdentifier(
2853 qryColumns.FieldByName('RDB$FIELD_NAME').AsString));
2854 qryColumns.Next;
2855 if not qryColumns.Eof then
2856 SList.Strings[SList.Count - 1] := SList.Strings[SList.Count - 1] + ', ';
2857 end;
2858 qryColumns.Close;
2859 SList.Text := SList.Text + Format(') AS%s', [LineEnding]);
2860 if not qryView.FieldByName('RDB$VIEW_SOURCE').IsNull then
2861 SList.Text := SList.Text + qryView.FieldByName('RDB$VIEW_SOURCE').AsString;
2862 SList.Text := SList.Text + Format('%s%s', [Term, LineEnding]);
2863 FMetaData.AddStrings(SList);
2864 SList.Clear;
2865 qryView.Next;
2866 end;
2867 finally
2868 qryView.Free;
2869 qryColumns.Free;
2870 SList.Free;
2871 end;
2872 end;
2873
2874 { PrintSet
2875 Functional description
2876 print (using ISQL_printf) the word "SET"
2877 if the first line of the ALTER DATABASE
2878 settings options. Also, add trailing
2879 comma for end of prior line if needed.
2880
2881 uses Print_buffer, a global }
2882
2883 function TIBExtract.PrintSet(var Used: Boolean) : String;
2884 begin
2885 if not Used then
2886 begin
2887 Result := ' SET ';
2888 Used := true;
2889 end
2890 else
2891 Result := Format(', %s ', [LineEnding]);
2892 end;
2893
2894 {
2895 PrintValidation
2896 Functional description
2897 This does some minor syntax adjustmet for extracting
2898 validation blobs and computed fields.
2899 if it does not start with the word CHECK
2900 if this is a computed field blob,look for () or insert them.
2901 if flag = false, this is a validation clause,
2902 if flag = true, this is a computed field }
2903
2904 function TIBExtract.PrintValidation(ToValidate: String;
2905 flag: Boolean): String;
2906 var
2907 IsSQL : Boolean;
2908 begin
2909 IsSql := false;
2910
2911 Result := '';
2912 ToValidate := Trim(ToValidate);
2913
2914 if flag then
2915 begin
2916 if ToValidate[1] = '(' then
2917 IsSQL := true;
2918 end
2919 else
2920 if (Pos(ToValidate, 'check') = 1) or (Pos(ToValidate, 'CHECK') = 1) then
2921 IsSQL := TRUE;
2922
2923 if not IsSQL then
2924 begin
2925 if Flag then
2926 Result := Result + '/* ' + ToValidate + ' */'
2927 else
2928 Result := Result + '(' + ToValidate + ')';
2929 end
2930 else
2931 Result := ToValidate;
2932 end;
2933
2934 procedure TIBExtract.SetDatabase(const Value: TIBDatabase);
2935 begin
2936 if (csLoading in ComponentState) or (FDatabase <> Value) then
2937 begin
2938 FDatabase := Value;
2939 if (not Assigned(FTransaction)) and (FDatabase <> nil) then
2940 Transaction := FDatabase.DefaultTransaction;
2941 FDatabaseInfo.Database := FDatabase;
2942 end;
2943 end;
2944
2945 procedure TIBExtract.SetTransaction(const Value: TIBTransaction);
2946 begin
2947 if FTransaction <> Value then
2948 begin
2949 FTransaction := Value;
2950 if (not Assigned(FDatabase)) and (FTransaction <> nil) then
2951 Database := FTransaction.DefaultDatabase;
2952 end;
2953 end;
2954
2955 procedure TIBExtract.ExtractObject(ObjectType : TExtractObjectTypes;
2956 ObjectName : String = ''; ExtractTypes : TExtractTypes = []);
2957 var
2958 DidActivate : Boolean;
2959 begin
2960 DidActivate := false;
2961 if not FTransaction.Active then
2962 begin
2963 FTransaction.StartTransaction;
2964 DidActivate := true;
2965 end;
2966 FMetaData.Clear;
2967 if not CaseSensitiveObjectNames then
2968 ObjectName := ExtractIdentifier(FDatabaseInfo.DBSQLDialect,ObjectName);
2969 case ObjectType of
2970 eoDatabase : ExtractDDL(true, '', ExtractTypes);
2971 eoDomain :
2972 if etTable in ExtractTypes then
2973 ListDomains(ObjectName, etTable)
2974 else
2975 ListDomains(ObjectName);
2976 eoTable :
2977 begin
2978 if ObjectName <> '' then
2979 begin
2980 if etDomain in ExtractTypes then
2981 ListDomains(ObjectName, etTable);
2982 ExtractListTable(ObjectName, '', false);
2983 if etIndex in ExtractTypes then
2984 ListIndex(ObjectName, etTable);
2985 if etForeign in ExtractTypes then
2986 ListForeign(ObjectName, etTable);
2987 if etCheck in ExtractTypes then
2988 ListCheck(ObjectName, etTable);
2989 if etTrigger in ExtractTypes then
2990 begin
2991 if etGrant in ExtractTypes then
2992 ListTriggers(ObjectName, [etTable,etGrant])
2993 else
2994 ListTriggers(ObjectName, [etTable]);
2995 end;
2996 if etGrant in ExtractTypes then
2997 ShowGrants(ObjectName, Term);
2998 if etData in ExtractTypes then
2999 ListData(ObjectName);
3000 end
3001 else
3002 ListAllTables(true);
3003 end;
3004 eoView :
3005 begin
3006 ListViews(ObjectName);
3007 if ObjectName <> '' then
3008 begin
3009 if etTrigger in ExtractTypes then
3010 begin
3011 if etGrant in ExtractTypes then
3012 ListTriggers(ObjectName, [etTable,etGrant])
3013 else
3014 ListTriggers(ObjectName, [etTable]);
3015 end;
3016 if etGrant in ExtractTypes then
3017 ShowGrants(ObjectName, Term);
3018 end;
3019 end;
3020 eoProcedure :
3021 begin
3022 ListProcs(pdCreateProc,ObjectName,etGrant in ExtractTypes);
3023 if (ObjectName <> '' ) and (etGrant in ExtractTypes) then
3024 ShowGrants(ObjectName, Term);
3025 end;
3026 eoPackage:
3027 begin
3028 if DatabaseInfo.ODSMajorVersion >= ODS_VERSION12 then
3029 begin
3030 ListPackages(paBoth,ObjectName, etGrant in ExtractTypes);
3031 if (ObjectName <> '' ) and (etGrant in ExtractTypes) then
3032 ShowGrants(ObjectName, Term);
3033 end
3034 else
3035 IBError(ibxeODSVersionRequired,['12.0']);
3036 end;
3037 eoFunction : ListFunctions(ObjectName);
3038 eoGenerator : ListGenerators(ObjectName,ExtractTypes);
3039 eoException : ListException(ObjectName);
3040 eoBLOBFilter : ListFilters(ObjectName);
3041 eoRole : ListRoles(ObjectName,etGrant in ExtractTypes);
3042 eoTrigger :
3043 if etTable in ExtractTypes then
3044 begin
3045 if etGrant in ExtractTypes then
3046 ListTriggers(ObjectName, [etTable,etGrant])
3047 else
3048 ListTriggers(ObjectName, [etTable])
3049 end
3050 else
3051 if etGrant in ExtractTypes then
3052 ListTriggers(ObjectName,[etTrigger,etGrant])
3053 else
3054 ListTriggers(ObjectName);
3055 eoForeign :
3056 if etTable in ExtractTypes then
3057 ListForeign(ObjectName, etTable)
3058 else
3059 ListForeign(ObjectName);
3060 eoIndexes :
3061 if etTable in ExtractTypes then
3062 ListIndex(ObjectName, etTable)
3063 else
3064 ListIndex(ObjectName);
3065 eoChecks :
3066 if etTable in ExtractTypes then
3067 ListCheck(ObjectName, etTable)
3068 else
3069 ListCheck(ObjectName);
3070 eoData : ListData(ObjectName);
3071 end;
3072 if DidActivate then
3073 FTransaction.Commit;
3074 end;
3075
3076 function TIBExtract.GetFieldType(FieldType, FieldSubType, FieldScale,
3077 FieldSize, FieldPrec, FieldLen: Integer): String;
3078 var
3079 i : Integer;
3080 PrecisionKnown : Boolean;
3081 begin
3082 Result := '';
3083 for i := Low(ColumnTypes) to High(ColumnTypes) do
3084 if FieldType = ColumnTypes[i].SQLType then
3085 begin
3086 PrecisionKnown := FALSE;
3087 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
3088 begin
3089 if FieldType in [blr_short, blr_long, blr_int64] then
3090 begin
3091 { We are ODS >= 10 and could be any Dialect }
3092 if (FDatabaseInfo.DBSQLDialect >= 3) and
3093 (FieldPrec <> 0) and
3094 (FieldSubType > 0) and
3095 (FieldSubType <= MAX_INTSUBTYPES) then
3096 begin
3097 Result := Result + Format('%s(%d, %d)', [
3098 IntegralSubtypes [FieldSubType],
3099 FieldPrec,
3100 -1 * FieldScale]);
3101 PrecisionKnown := true;
3102 end;
3103 end;
3104 end;
3105 if PrecisionKnown = false then
3106 begin
3107 { Take a stab at numerics and decimals }
3108 if (FieldType = blr_short) and
3109 (FieldScale < 0) then
3110 Result := Result + Format('NUMERIC(4, %d)',
3111 [-FieldScale] )
3112 else
3113 if (FieldType = blr_long) and
3114 (FieldScale < 0) then
3115 Result := Result + Format('NUMERIC(9, %d)',
3116 [-FieldScale] )
3117 else
3118 if (FieldType = blr_double) and
3119 (FieldScale < 0) then
3120 Result := Result + Format('NUMERIC(15, %d)',
3121 [-FieldScale] )
3122 else
3123 Result := Result + ColumnTypes[i].TypeName;
3124 end;
3125 break;
3126 end;
3127 if (FieldType in [blr_text, blr_varying]) and
3128 (FieldSize <> 0) then
3129 Result := Result + Format('(%d)', [FieldSize]);
3130 end;
3131
3132 { S H O W _ g r a n t s
3133 Functional description
3134 Show grants for given object name
3135 This function is also called by extract for privileges.
3136 It must extract granted privileges on tables/views to users,
3137 - these may be compound, so put them on the same line.
3138 Grant execute privilege on procedures to users
3139 Grant various privileges to procedures.
3140 All privileges may have the with_grant option set. }
3141
3142 procedure TIBExtract.ShowGrants(MetaObject: String; Terminator: String;
3143 NoUserGrants: boolean);
3144 const
3145 GrantsBaseSelect =
3146 'Select Trim(RDB$USER) as RDB$USER,List("Privileges") as Privileges, '+
3147 'coalesce(RDB$GRANT_OPTION,0) as RDB$GRANT_OPTION,METAOBJECTNAME, '+
3148 'RDB$USER_TYPE, RDB$OBJECT_TYPE, '+
3149 'case T2.RDB$TYPE_NAME '+
3150 ' When ''RELATION'' then ''TABLE'' '+
3151 ' When ''FIELD'' then ''DOMAIN'' '+
3152 'Else T2.RDB$TYPE_NAME End as OBJECT_TYPE_NAME, '+
3153 'T1.RDB$TYPE_NAME as USER_TYPE_NAME, '+
3154 'case '+
3155 'When coalesce(RDB$GRANT_OPTION,0) <> 0 and RDB$USER_TYPE = 13 then '' WITH ADMIN OPTION'' '+
3156 'When coalesce(RDB$GRANT_OPTION,0) <> 0 and RDB$USER_TYPE <> 13 then '' WITH GRANT OPTION'' '+
3157 'ELSE '''' End as GRANTOPTION, '+
3158 'case When RDB$OWNER_NAME = RDB$GRANTOR then NULL '+
3159 'else Trim(RDB$GRANTOR) End as GRANTEDBY '+
3160 'From ( '+
3161 'Select PR.RDB$USER,PR.RDB$RELATION_NAME as METAOBJECTNAME, LIST(DISTINCT Trim(Case PR.RDB$PRIVILEGE '+
3162 'When ''X'' then ''EXECUTE'' '+
3163 'When ''S'' then ''SELECT'' '+
3164 'When ''U'' then ''UPDATE'' '+
3165 'When ''D'' then ''DELETE'' '+
3166 'When ''R'' then ''REFERENCES'' '+
3167 'When ''G'' then ''USAGE'' '+
3168 'When ''I'' then ''INSERT'' '+
3169 'end )) as "Privileges", '+
3170 'PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE,OW.RDB$OWNER_NAME,PR.RDB$GRANTOR '+
3171 'FROM RDB$USER_PRIVILEGES PR '+
3172 'JOIN ObjectOwners OW On OW.METAOBJECTNAME = PR.RDB$RELATION_NAME and OW.ObjectType = PR.RDB$OBJECT_TYPE '+
3173 'Where PR.RDB$PRIVILEGE <> ''M'' and (PR.RDB$PRIVILEGE <> ''U'' or PR.RDB$FIELD_NAME is null) '+
3174 'Group By PR.RDB$USER,PR.RDB$RELATION_NAME,PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE,OW.RDB$OWNER_NAME,PR.RDB$GRANTOR '+
3175 'UNION '+
3176 'Select PR.RDB$USER,PR.RDB$RELATION_NAME, ''Update('' || List(Trim(PR.RDB$FIELD_NAME)) || '')'', '+
3177 'PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE, OW.RDB$OWNER_NAME,PR.RDB$GRANTOR '+
3178 'FROM RDB$USER_PRIVILEGES PR '+
3179 'JOIN ObjectOwners OW On OW.METAOBJECTNAME = PR.RDB$RELATION_NAME and OW.ObjectType = PR.RDB$OBJECT_TYPE '+
3180 'Where PR.RDB$PRIVILEGE = ''U'' and PR.RDB$FIELD_NAME is not null '+
3181 'Group By PR.RDB$USER,PR.RDB$RELATION_NAME,PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE, OW.RDB$OWNER_NAME,PR.RDB$GRANTOR) A '+
3182 'JOIN RDB$TYPES T1 On T1.RDB$TYPE = RDB$USER_TYPE and T1.RDB$FIELD_NAME = ''RDB$OBJECT_TYPE'' '+
3183 'JOIN RDB$TYPES T2 On T2.RDB$TYPE = RDB$OBJECT_TYPE and T2.RDB$FIELD_NAME = ''RDB$OBJECT_TYPE'' '+
3184 'Where METAOBJECTNAME = :METAOBJECTNAME and RDB$USER <> RDB$OWNER_NAME '+
3185 'Group By RDB$USER,RDB$GRANT_OPTION, RDB$USER_TYPE, RDB$OBJECT_TYPE,METAOBJECTNAME,RDB$GRANTOR,T2.RDB$TYPE_NAME,T1.RDB$TYPE_NAME,RDB$OWNER_NAME '+
3186 'ORDER BY RDB$USER, RDB$OBJECT_TYPE';
3187
3188 GrantsSQL12 =
3189 'with ObjectOwners As ( '+
3190 ' Select RDB$RELATION_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 0 as ObjectType '+
3191 ' From RDB$RELATIONS '+
3192 ' UNION '+
3193 ' Select RDB$PROCEDURE_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 5 as ObjectType '+
3194 ' From RDB$PROCEDURES '+
3195 ' UNION '+
3196 ' Select RDB$EXCEPTION_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 7 as ObjectType '+
3197 ' From RDB$EXCEPTIONS '+
3198 ' UNION '+
3199 ' Select RDB$FIELD_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 9 as ObjectType '+
3200 ' From RDB$FIELDS Where RDB$FIELD_NAME not Similar to ''RDB$%|SEC$%|MON$%|SQL$%'' '+
3201 ' UNION '+
3202 ' Select RDB$GENERATOR_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 14 as ObjectType '+
3203 ' From RDB$GENERATORS '+
3204 ' UNION '+
3205 ' Select RDB$CHARACTER_SET_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 11 as ObjectType '+
3206 ' From RDB$CHARACTER_SETS '+
3207 ' UNION '+
3208 ' Select RDB$COLLATION_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 17 as ObjectType '+
3209 ' From RDB$COLLATIONS '+
3210 ' UNION '+
3211 ' Select RDB$PACKAGE_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 18 as ObjectType '+
3212 ' From RDB$PACKAGES '+
3213 ') '+ GrantsBaseSelect;
3214
3215 GrantsSQL =
3216 'with ObjectOwners As ( '+
3217 'Select RDB$RELATION_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 0 as ObjectType '+
3218 'From RDB$RELATIONS '+
3219 'UNION '+
3220 'Select RDB$PROCEDURE_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 5 as ObjectType '+
3221 'From RDB$PROCEDURES '+
3222 'UNION '+
3223 'Select RDB$EXCEPTION_NAME as METAOBJECTNAME, ''SYSDBA'', 7 as ObjectType '+
3224 'From RDB$EXCEPTIONS '+
3225 'UNION '+
3226 'Select RDB$GENERATOR_NAME as METAOBJECTNAME, ''SYSDBA'', 14 as ObjectType '+
3227 'From RDB$GENERATORS '+
3228 'UNION '+
3229 'Select RDB$CHARACTER_SET_NAME as METAOBJECTNAME, ''SYSDBA'', 11 as ObjectType '+
3230 'From RDB$CHARACTER_SETS '+
3231 ') '+ GrantsBaseSelect;
3232
3233 var qryOwnerPriv : TIBSQL;
3234
3235 begin
3236 if MetaObject = '' then
3237 exit;
3238
3239 qryOwnerPriv := TIBSQL.Create(FDatabase);
3240 try
3241 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION12 then
3242 qryOwnerPriv.SQL.Text := GrantsSQL12
3243 else
3244 qryOwnerPriv.SQL.Text := GrantsSQL;
3245 qryOwnerPriv.Params.ByName('METAOBJECTNAME').AsString := MetaObject;
3246 qryOwnerPriv.ExecQuery;
3247 while not qryOwnerPriv.Eof do
3248 begin
3249 if not NoUserGrants or (qryOwnerPriv.FieldByName('RDB$USER_TYPE').AsInteger <> obj_user)
3250 or (qryOwnerPriv.FieldByName('RDB$USER').AsString = 'PUBLIC') then
3251 begin
3252 if qryOwnerPriv.FieldByName('GRANTEDBY').IsNull then
3253 FMetaData.Add(Format('GRANT %s ON %s %s TO %s %s %s %s', [
3254 qryOwnerPriv.FieldByName('Privileges').AsString,
3255 qryOwnerPriv.FieldByName('OBJECT_TYPE_NAME').AsString,
3256 QuoteIdentifier(qryOwnerPriv.FieldByName('METAOBJECTNAME').AsString),
3257 qryOwnerPriv.FieldByName('USER_TYPE_NAME').AsString,
3258 QuoteIdentifier(qryOwnerPriv.FieldByName('RDB$USER').AsString),
3259 qryOwnerPriv.FieldByName('GRANTOPTION').AsString,
3260 Terminator]))
3261 else
3262 FMetaData.Add(Format('GRANT %s ON %s %s TO %s %s %s GRANTED BY %s %s', [
3263 qryOwnerPriv.FieldByName('Privileges').AsString,
3264 qryOwnerPriv.FieldByName('OBJECT_TYPE_NAME').AsString,
3265 QuoteIdentifier(qryOwnerPriv.FieldByName('METAOBJECTNAME').AsString),
3266 qryOwnerPriv.FieldByName('USER_TYPE_NAME').AsString,
3267 QuoteIdentifier(qryOwnerPriv.FieldByName('RDB$USER').AsString),
3268 qryOwnerPriv.FieldByName('GRANTOPTION').AsString,
3269 QuoteIdentifier(qryOwnerPriv.FieldByName('GRANTEDBY').AsString),
3270 Terminator]));
3271 end;
3272 qryOwnerPriv.Next;
3273 end;
3274 qryOwnerPriv.Close;
3275 finally
3276 qryOwnerPriv.Free;
3277 end;
3278 end;
3279
3280 procedure TIBExtract.ShowGrantsTo(MetaObject: String; ObjectType: integer; Terminator: String);
3281 const
3282 GrantsSQL =
3283 'Select Trim(RDB$USER) as RDB$USER,List("Privileges") as Privileges, '+
3284 'coalesce(RDB$GRANT_OPTION,0) as RDB$GRANT_OPTION,METAOBJECTNAME, '+
3285 'RDB$USER_TYPE, RDB$OBJECT_TYPE, '+
3286 'case RDB$OBJECT_TYPE '+
3287 'When 0 then ''TABLE'' '+
3288 'When 5 then ''PROCEDURE'' '+
3289 'When 7 then ''EXCEPTION'' '+
3290 'When 11 then ''CHARACTER SET'' '+
3291 'ELSE NULL END as OBJECT_TYPE_NAME, '+
3292 'case RDB$USER_TYPE '+
3293 'When 5 then ''PROCEDURE'' '+
3294 'When 2 then ''TRIGGER'' '+
3295 'When 8 then ''USER'' '+
3296 'When 13 then ''ROLE'' '+
3297 'ELSE NULL END as USER_TYPE_NAME, '+
3298 'case '+
3299 'When coalesce(RDB$GRANT_OPTION,0) <> 0 and RDB$USER_TYPE = 13 then '' WITH ADMIN OPTION'' '+
3300 'When coalesce(RDB$GRANT_OPTION,0) <> 0 and RDB$USER_TYPE <> 13 then '' WITH GRANT OPTION'' '+
3301 'ELSE '''' End as GRANTOPTION '+
3302 'From ( '+
3303 'Select PR.RDB$USER,PR.RDB$RELATION_NAME as METAOBJECTNAME, LIST(DISTINCT Trim(Case PR.RDB$PRIVILEGE '+
3304 'When ''X'' then ''EXECUTE'' '+
3305 'When ''S'' then ''SELECT'' '+
3306 'When ''U'' then ''UPDATE'' '+
3307 'When ''D'' then ''DELETE'' '+
3308 'When ''R'' then ''REFERENCES'' '+
3309 'When ''G'' then ''USAGE'' '+
3310 'When ''I'' then ''INSERT'' end )) as "Privileges", '+
3311 'PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE '+
3312 'FROM RDB$USER_PRIVILEGES PR '+
3313 'Where PR.RDB$PRIVILEGE <> ''M'' and (PR.RDB$PRIVILEGE <> ''U'' or PR.RDB$FIELD_NAME is null) '+
3314 'Group By PR.RDB$USER,PR.RDB$RELATION_NAME,PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE '+
3315 'UNION '+
3316 'Select PR.RDB$USER,PR.RDB$RELATION_NAME, ''Update('' || List(Trim(PR.RDB$FIELD_NAME)) || '')'', '+
3317 'PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE '+
3318 'FROM RDB$USER_PRIVILEGES PR '+
3319 'Where PR.RDB$PRIVILEGE = ''U'' and PR.RDB$FIELD_NAME is not null '+
3320 'Group By PR.RDB$USER,PR.RDB$RELATION_NAME,PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE) '+
3321 'Where RDB$USER = :METAOBJECTNAME and RDB$USER_TYPE = :USERTYPE '+
3322 'Group By RDB$USER,RDB$GRANT_OPTION, RDB$USER_TYPE, RDB$OBJECT_TYPE, METAOBJECTNAME '+
3323 'ORDER BY METAOBJECTNAME';
3324
3325 var qryOwnerPriv : TIBSQL;
3326
3327 begin
3328 if MetaObject = '' then
3329 exit;
3330
3331 qryOwnerPriv := TIBSQL.Create(FDatabase);
3332 try
3333 qryOwnerPriv.SQL.Text := GrantsSQL;
3334 qryOwnerPriv.Params.ByName('METAOBJECTNAME').AsString := MetaObject;
3335 qryOwnerPriv.Params.ByName('USERTYPE').AsInteger := ObjectType;
3336 qryOwnerPriv.ExecQuery;
3337 while not qryOwnerPriv.Eof do
3338 begin
3339 FMetaData.Add(Format('GRANT %s ON %s %s TO %s %s %s%s', [
3340 qryOwnerPriv.FieldByName('Privileges').AsString,
3341 qryOwnerPriv.FieldByName('OBJECT_TYPE_NAME').AsString,
3342 QuoteIdentifier(qryOwnerPriv.FieldByName('METAOBJECTNAME').AsString),
3343 qryOwnerPriv.FieldByName('USER_TYPE_NAME').AsString,
3344 QuoteIdentifier(qryOwnerPriv.FieldByName('RDB$USER').AsString),
3345 qryOwnerPriv.FieldByName('GRANTOPTION').AsString,
3346 Terminator]));
3347 qryOwnerPriv.Next;
3348 end;
3349 qryOwnerPriv.Close;
3350 finally
3351 qryOwnerPriv.Free;
3352 end;
3353 FMetaData.Add('');
3354 end;
3355
3356 { ShowGrantRoles
3357 Functional description
3358 Show grants for given role name
3359 This function is also called by extract for privileges.
3360 All membership privilege may have the with_admin option set. }
3361
3362 procedure TIBExtract.ShowGrantRoles(Terminator: String);
3363 const
3364 RoleSQL =
3365 'SELECT RDB$USER, RDB$GRANT_OPTION, RDB$RELATION_NAME ' +
3366 'FROM RDB$USER_PRIVILEGES ' +
3367 'WHERE ' +
3368 ' RDB$OBJECT_TYPE = %d AND ' +
3369 ' RDB$USER_TYPE = %d AND ' +
3370 ' RDB$PRIVILEGE = ''M'' ' +
3371 'ORDER BY RDB$RELATION_NAME, RDB$USER';
3372
3373 var
3374 WithOption, UserString : String;
3375 qryRole : TIBSQL;
3376
3377 begin
3378 qryRole := TIBSQL.Create(FDatabase);
3379 try
3380 qryRole.SQL.Text := Format(RoleSQL, [obj_sql_role, obj_user]);
3381 qryRole.ExecQuery;
3382 while not qryRole.Eof do
3383 begin
3384 UserString := Trim(qryRole.FieldByName('RDB$USER').AsString);
3385
3386 if (not qryRole.FieldByName('RDB$GRANT_OPTION').IsNull) and
3387 (qryRole.FieldByName('RDB$GRANT_OPTION').AsInteger = 1) then
3388 WithOption := ' WITH ADMIN OPTION'
3389 else
3390 WithOption := '';
3391 FMetaData.Add(Format('GRANT %s TO %s%s%s%s',
3392 [ QuoteIdentifier( qryRole.FieldByName('RDB$RELATION_NAME').AsString),
3393 UserString, WithOption, Terminator, LineEnding]));
3394
3395 qryRole.Next;
3396 end;
3397 finally
3398 qryRole.Free;
3399 end;
3400 end;
3401
3402 { GetProcedureArgs
3403 Functional description
3404 This function extract the procedure parameters and adds it to the
3405 extract file }
3406
3407 procedure TIBExtract.GetProcedureArgs(Proc: String);
3408 const
3409 { query to retrieve the input parameters. }
3410 ProcHeaderSQL =
3411 'SELECT * ' +
3412 ' FROM RDB$PROCEDURE_PARAMETERS PRM JOIN RDB$FIELDS FLD ON ' +
3413 ' PRM.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME ' +
3414 'WHERE ' +
3415 ' PRM.RDB$PROCEDURE_NAME = :PROCNAME AND ' +
3416 ' PRM.RDB$PARAMETER_TYPE = :Input ' +
3417 'ORDER BY PRM.RDB$PARAMETER_NUMBER';
3418
3419 var
3420 FirstTime, PrecisionKnown : Boolean;
3421 Line : String;
3422 qryHeader : TIBSQL;
3423
3424 function FormatParamStr : String;
3425 var
3426 i, CollationID, CharSetID : Integer;
3427 begin
3428 Result := Format(' %s ', [qryHeader.FieldByName('RDB$PARAMETER_NAME').AsString]);
3429 for i := Low(ColumnTypes) to High(ColumnTypes) do
3430 if qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger = ColumnTypes[i].SQLType then
3431 begin
3432 PrecisionKnown := FALSE;
3433 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
3434 begin
3435 if qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_short, blr_long, blr_int64] then
3436 begin
3437 { We are ODS >= 10 and could be any Dialect }
3438 if (FDatabaseInfo.DBSQLDialect >= 3) and
3439 (not qryHeader.FieldByName('RDB$FIELD_PRECISION').IsNull) and
3440 (qryHeader.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger > 0) and
3441 (qryHeader.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger <= MAX_INTSUBTYPES) then
3442 begin
3443 Result := Result + Format('%s(%d, %d)', [
3444 IntegralSubtypes [qryHeader.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger],
3445 qryHeader.FieldByName('RDB$FIELD_PRECISION').AsInteger,
3446 -1 * qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger]);
3447 PrecisionKnown := true;
3448 end;
3449 end;
3450 end;
3451 if PrecisionKnown = false then
3452 begin
3453 { Take a stab at numerics and decimals }
3454 if (qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_short) and
3455 (qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then
3456 Result := Result + Format('NUMERIC(4, %d)',
3457 [-qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger] )
3458 else
3459 if (qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_long) and
3460 (qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then
3461 Result := Result + Format('NUMERIC(9, %d)',
3462 [-qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger] )
3463 else
3464 if (qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_double) and
3465 (qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then
3466 Result := Result + Format('NUMERIC(15, %d)',
3467 [-qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger] )
3468 else
3469 Result := Result + ColumnTypes[i].TypeName;
3470 end;
3471 break;
3472 end;
3473 if (qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_text, blr_varying]) then
3474 begin
3475 if not qryHeader.FieldByName('RDB$CHARACTER_LENGTH').IsNull then
3476 Result := Result + Format('(%d)', [qryHeader.FieldByName('RDB$CHARACTER_LENGTH').AsInteger])
3477 else
3478 Result := Result + Format('(%d)', [qryHeader.FieldByName('RDB$FIELD_LENGTH').AsInteger]);
3479 end;
3480
3481 { Show international character sets and collations }
3482
3483 if (not qryHeader.FieldByName('RDB$COLLATION_ID').IsNull) or
3484 (not qryHeader.FieldByName('RDB$CHARACTER_SET_ID').IsNull) then
3485 begin
3486 if qryHeader.FieldByName('RDB$COLLATION_ID').IsNull then
3487 CollationId := 0
3488 else
3489 CollationId := qryHeader.FieldByName('RDB$COLLATION_ID').AsInteger;
3490
3491 if qryHeader.FieldByName('RDB$CHARACTER_SET_ID').IsNull then
3492 CharSetId := 0
3493 else
3494 CharSetId := qryHeader.FieldByName('RDB$CHARACTER_SET_ID').AsInteger;
3495
3496 Result := Result + GetCharacterSets(CharSetId, CollationId, false);
3497 end;
3498 end;
3499
3500 begin
3501 FirstTime := true;
3502 qryHeader := TIBSQL.Create(FDatabase);
3503 try
3504 qryHeader.SQL.Text := ProcHeaderSQL;
3505 qryHeader.Params.ByName('procname').AsString := Proc;
3506 qryHeader.Params.ByName('Input').AsInteger := 0;
3507 qryHeader.ExecQuery;
3508 while not qryHeader.Eof do
3509 begin
3510 if FirstTime then
3511 begin
3512 FirstTime := false;
3513 FMetaData.Add('(');
3514 end;
3515
3516 Line := FormatParamStr;
3517
3518 qryHeader.Next;
3519 if not qryHeader.Eof then
3520 Line := Line + ',';
3521 FMetaData.Add(Line);
3522 end;
3523
3524 { If there was at least one param, close parens }
3525 if not FirstTime then
3526 begin
3527 FMetaData.Add( ')');
3528 end;
3529
3530 FirstTime := true;
3531 qryHeader.Close;
3532 qryHeader.Params.ByName('Input').AsInteger := 1;
3533 qryHeader.ExecQuery;
3534
3535 while not qryHeader.Eof do
3536 begin
3537 if FirstTime then
3538 begin
3539 FirstTime := false;
3540 FMetaData.Add('RETURNS' + LineEnding + '(');
3541 end;
3542
3543 Line := FormatParamStr;
3544
3545 qryHeader.Next;
3546 if not qryHeader.Eof then
3547 Line := Line + ',';
3548 FMetaData.Add(Line);
3549 end;
3550
3551 { If there was at least one param, close parens }
3552 if not FirstTime then
3553 begin
3554 FMetaData.Add( ')');
3555 end;
3556
3557 FMetaData.Add('AS');
3558 finally
3559 qryHeader.Free;
3560 end;
3561 end;
3562
3563 procedure TIBExtract.Notification(AComponent: TComponent;
3564 Operation: TOperation);
3565 begin
3566 inherited;
3567 if (AComponent = FDatabase) and (Operation = opRemove) then
3568 FDatabase := nil;
3569 if (AComponent = FTransaction) and (Operation = opRemove) then
3570 FTransaction := nil;
3571 end;
3572
3573 function TIBExtract.QuoteIdentifier(Value: String): String;
3574 begin
3575 if AlwaysQuoteIdentifiers then
3576 Result := IBUtils.QuoteIdentifier(FDatabase.DBSQLDialect,Value)
3577 else
3578 Result := IBUtils.QuoteIdentifierIfNeeded(FDatabase.DBSQLDialect,Value)
3579 end;
3580
3581 procedure TIBExtract.ListData(ObjectName: String);
3582 const
3583 SelectFieldListSQL = 'Select List(RDB$FIELD_NAME) From ( '+
3584 'Select RF.RDB$FIELD_NAME From RDB$RELATION_FIELDS RF '+
3585 'JOIN RDB$FIELDS F On F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE '+
3586 'Where F.RDB$COMPUTED_BLR is NULL and RF.RDB$RELATION_NAME = Upper(:Relation) '+
3587 'Order by RF.RDB$FIELD_POSITION asc)';
3588
3589 TableSQL =
3590 'SELECT * FROM RDB$RELATIONS ' +
3591 'WHERE ' +
3592 ' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' +
3593 ' RDB$VIEW_BLR IS NULL ' +
3594 'ORDER BY RDB$RELATION_NAME';
3595
3596 var FieldList: string;
3597
3598 begin
3599 if ObjectName = '' then {List all}
3600 begin
3601 with TIBSQL.Create(self) do
3602 try
3603 Database := FDatabase;
3604 SQL.Text := TableSQL;
3605 ExecQuery;
3606 FMetaData.Add('/* Data Starts */');
3607 while not EOF do
3608 begin
3609 ListData(Trim(FieldByName('RDB$RELATION_NAME').AsString));
3610 Next;
3611 end;
3612 FMetaData.Add('/* Data Ends */');
3613 finally
3614 Free;
3615 end;
3616 end
3617 else
3618 begin
3619 FieldList := '*';
3620 with TIBSQL.Create(self) do
3621 try
3622 Database := FDatabase;
3623 SQL.Text := SelectFieldListSQL;
3624 Params[0].AsString := ObjectName;
3625 ExecQuery;
3626 try
3627 if not EOF then
3628 FieldList := Fields[0].AsString;
3629 finally
3630 Close;
3631 end;
3632 finally
3633 Free
3634 end;
3635
3636 with TIBInsertStmtsOut.Create(self) do
3637 try
3638 Database := FDatabase;
3639 if DataOut(Format('Select %s From %s',[FieldList,QuoteIdentifier( ObjectName)]),
3640 Add2MetaData) then
3641 FMetaData.Add('COMMIT;');
3642 finally
3643 Free
3644 end;
3645 end;
3646 end;
3647
3648 procedure TIBExtract.ListRoles(ObjectName: String; IncludeGrants: boolean);
3649 const
3650 RolesSQL =
3651 'select * from RDB$ROLES WHERE RDB$SYSTEM_FLAG = 0 ' +
3652 'order by RDB$ROLE_NAME';
3653
3654 RolesByNameSQL =
3655 'select * from RDB$ROLES ' +
3656 'WHERE RDB$ROLE_NAME = :RoleName ' +
3657 'order by RDB$ROLE_NAME';
3658
3659 var
3660 qryRoles : TIBSQL;
3661 PrevOwner, RoleName, OwnerName : String;
3662 begin
3663 {Process GRANT roles}
3664 qryRoles := TIBSQL.Create(FDatabase);
3665 try
3666 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION9 then
3667 begin
3668 PrevOwner := '';
3669 FMetaData.Add('');
3670 FMetaData.Add('/* Grant Roles for this database */');
3671 FMetaData.Add('');
3672
3673 if ObjectName = '' then
3674 qryRoles.SQL.Text := RolesSQL
3675 else
3676 begin
3677 qryRoles.SQL.Text := RolesByNameSQL;
3678 qryRoles.Params.ByName('RoleName').AsString := ObjectName;
3679 end;
3680 qryRoles.ExecQuery;
3681 try
3682 while not qryRoles.Eof do
3683 begin
3684 RoleName := QuoteIdentifier(
3685 qryRoles.FieldByName('rdb$Role_Name').AsString);
3686 OwnerName := Trim(qryRoles.FieldByName('rdb$Owner_Name').AsString);
3687 if PrevOwner <> OwnerName then
3688 begin
3689 FMetaData.Add('');
3690 FMetaData.Add(Format('/* Role: %s, Owner: %s */', [RoleName, OwnerName]));
3691 FMetaData.Add('');
3692 PrevOwner := OwnerName;
3693 end;
3694 FMetaData.Add('CREATE ROLE ' + RoleName + Term);
3695 if IncludeGrants then
3696 ShowGrantsTo(qryRoles.FieldByName('rdb$Role_Name').AsString,obj_sql_role,Term);
3697 qryRoles.Next;
3698 end;
3699 finally
3700 qryRoles.Close;
3701 end;
3702 end;
3703 finally
3704 qryRoles.Free;
3705 end;
3706 end;
3707
3708 end.
3709
3710