ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/IBExtract.pas
Revision: 319
Committed: Thu Feb 25 12:05:40 2021 UTC (3 years, 1 month ago) by tony
Content type: text/x-pascal
File size: 154634 byte(s)
Log Message:
Merge into public release

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