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