ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/IBExtract.pas
Revision: 349
Committed: Mon Oct 18 08:39:40 2021 UTC (2 years, 6 months ago) by tony
Content type: text/x-pascal
File size: 155048 byte(s)
Log Message:
FIxes Merged

File Contents

# Content
1 {************************************************************************}
2 { }
3 { The contents of this file are subject to the InterBase }
4 { Public License Version 1.0 (the "License"); you may not }
5 { use this file except in compliance with the License. You }
6 { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
7 { Software distributed under the License is distributed on }
8 { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
9 { express or implied. See the License for the specific language }
10 { governing rights and limitations under the License. }
11 { }
12 { The Original Code was created by Jeff Overcash. }
13 { Portions based upon code by Inprise Corporation are Copyright (C) }
14 { Inprise Corporation. All Rights Reserved. }
15 { }
16 { IBX Version 4.2 or higher required }
17 { Contributor(s): Jeff Overcash }
18 { }
19 { IBX For Lazarus (Firebird Express) }
20 { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
21 { Portions created by MWA Software are copyright McCallum Whyman }
22 { Associates Ltd 2011 - 2018 }
23 { }
24 {************************************************************************}
25
26 { Syntax Enhancements Supported (by Firebird Version no.):
27
28 Multi-action triggers (1.5)
29 CREATE SEQUENCE (2.0)
30 Database Triggers (2.1)
31 Global Temporary Tables (2.1)
32 Boolean Type (3.0)
33 Identity Column Type (3.0)
34 DDL Triggers (3.0)
35 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';
1522 PackageBodySQL = 'CREATE PACKAGE BODY %s%sAS';
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 := Trim(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]));
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,LineEnding]));
1576 SList.Text := qryPackages.FieldByName('RDB$PACKAGE_BODY_SOURCE').AsString;
1577 SList.Add(Format('%s%s', [ProcTerm, LineEnding]));
1578 ExtractOut(SList);
1579 end;
1580
1581 if IncludeGrants then
1582 ShowGrantsTo(aPackageName,obj_package,ProcTerm);
1583 qryPackages.Next;
1584 end;
1585 qryPackages.Close;
1586
1587 if not Header then
1588 begin
1589 ExtractOut(Format('SET TERM %s%s', [Term, ProcTerm]));
1590 ExtractOut('COMMIT WORK;');
1591 ExtractOut('SET AUTODDL ON;');
1592 end;
1593 ExtractOut(Comments);
1594 finally
1595 Comments.Free;
1596 SList.Free;
1597 qryPackages.Free;
1598 end;
1599 end;
1600
1601 { ListAllProcs
1602 Functional description
1603 Shows text of a stored procedure given a name.
1604 or lists procedures if no argument.
1605 Since procedures may reference each other, we will create all
1606 dummy procedures of the correct name, then alter these to their
1607 correct form.
1608 Add the parameter names when these procedures are created.
1609
1610 procname -- Name of procedure to investigate }
1611
1612 procedure TIBExtract.ListProcs(ProcDDLType: TProcDDLType;
1613 ProcedureName: String; IncludeGrants: boolean);
1614 const
1615 CreateProcedureStr1 = 'CREATE PROCEDURE %s';
1616 CreateProcedureStr2 = 'BEGIN EXIT; END';
1617 CreateProcedureStr3 = 'BEGIN SUSPEND; EXIT; END';
1618 ProcedureSQL = {Order procedures by dependency order and then procedure name}
1619 'with recursive Procs as ( ' +
1620 'Select RDB$PROCEDURE_NAME, 1 as ProcLevel from RDB$PROCEDURES ' +
1621 'UNION ALL ' +
1622 'Select D.RDB$DEPENDED_ON_NAME, ProcLevel + 1 From RDB$DEPENDENCIES D ' +
1623 'JOIN Procs on Procs.RDB$PROCEDURE_NAME = D.RDB$DEPENDENT_NAME ' +
1624 ' and Procs.RDB$PROCEDURE_NAME <> D.RDB$DEPENDED_ON_NAME ' +
1625 'JOIN RDB$PROCEDURES P On P.RDB$PROCEDURE_NAME = D.RDB$DEPENDED_ON_NAME ' +
1626 ' ) ' +
1627 'SELECT * FROM RDB$PROCEDURES P ' +
1628 'JOIN ( ' +
1629 'Select RDB$PROCEDURE_NAME, max(ProcLevel) as ProcLevel From Procs ' +
1630 'Group By RDB$PROCEDURE_NAME) A On A.RDB$PROCEDURE_NAME = P.RDB$PROCEDURE_NAME ' +
1631 'Order by A.ProcLevel desc, P.RDB$PROCEDURE_NAME asc';
1632
1633 ProcedureSQLODS12 = {Order procedures by dependency order and then procedure name}
1634 'with recursive Procs as ( ' +
1635 'Select RDB$PROCEDURE_NAME, 1 as ProcLevel from RDB$PROCEDURES ' +
1636 'UNION ALL ' +
1637 'Select D.RDB$DEPENDED_ON_NAME, ProcLevel + 1 From RDB$DEPENDENCIES D ' +
1638 'JOIN Procs on Procs.RDB$PROCEDURE_NAME = D.RDB$DEPENDENT_NAME ' +
1639 ' and Procs.RDB$PROCEDURE_NAME <> D.RDB$DEPENDED_ON_NAME ' +
1640 'JOIN RDB$PROCEDURES P On P.RDB$PROCEDURE_NAME = D.RDB$DEPENDED_ON_NAME ' +
1641 ' ) ' +
1642 'SELECT * FROM RDB$PROCEDURES P ' +
1643 'JOIN ( ' +
1644 'Select RDB$PROCEDURE_NAME, max(ProcLevel) as ProcLevel From Procs ' +
1645 'Group By RDB$PROCEDURE_NAME) A On A.RDB$PROCEDURE_NAME = P.RDB$PROCEDURE_NAME ' +
1646 'Where P.RDB$PACKAGE_NAME is NULL '+
1647 'Order by A.ProcLevel desc, P.RDB$PROCEDURE_NAME asc';
1648 ProcedureNameSQL =
1649 'SELECT * FROM RDB$PROCEDURES ' +
1650 'WHERE RDB$PROCEDURE_NAME = :ProcedureName ' +
1651 'ORDER BY RDB$PROCEDURE_NAME';
1652
1653 ProcedureSecuritySQL = 'Select RDB$SQL_SECURITY From RDB$PROCEDURES WHERE RDB$PROCEDURE_NAME = :ProcedureName';
1654
1655 var
1656 qryProcedures : TIBSQL;
1657 qryProcSecurity: TIBSQL;
1658 ProcName : String;
1659 SList : TStrings;
1660 Header : Boolean;
1661 Comments: TStrings;
1662 begin
1663 Header := true;
1664 qryProcedures := TIBSQL.Create(FDatabase);
1665 qryProcSecurity := TIBSQL.Create(FDatabase);
1666 Comments := TStringList.Create;
1667 SList := TStringList.Create;
1668 try
1669 if ProcedureName = '' then
1670 begin
1671 if DatabaseInfo.ODSMajorVersion < ODS_VERSION12 then
1672 qryProcedures.SQL.Text := ProcedureSQL
1673 else
1674 qryProcedures.SQL.Text := ProcedureSQLODS12;
1675 end
1676 else
1677 begin
1678 qryProcedures.SQL.Text := ProcedureNameSQL;
1679 qryProcedures.Params.ByName('ProcedureName').AsString := ProcedureName;
1680 end;
1681
1682 qryProcedures.ExecQuery;
1683 while not qryProcedures.Eof do
1684 begin
1685 if Header then
1686 begin
1687 ExtractOut('COMMIT WORK;');
1688 ExtractOut('SET AUTODDL OFF;');
1689 ExtractOut(Format('SET TERM %s%s', [ProcTerm, Term]));
1690 ExtractOut('');
1691 if ProcDDLType in [pdCreateStub,pdCreateProc] then
1692 ExtractOut('/* Stored procedures Definitions*/')
1693 else
1694 ExtractOut('/* Stored procedure Bodies */');
1695 ExtractOut('');
1696 Header := false;
1697 end;
1698 ProcName := Trim(qryProcedures.FieldByName('RDB$PROCEDURE_NAME').AsString);
1699
1700 case ProcDDLType of
1701 pdCreateStub:
1702 begin
1703 AddComment(qryProcedures,ctProcedure,Comments);
1704 ExtractOut(Format(CreateProcedureStr1, [QuoteIdentifier(
1705 ProcName)]));
1706 GetProcedureArgs(ProcName);
1707 if qryProcedures.FieldByName('RDB$PROCEDURE_TYPE').AsInteger = 1 then
1708 ExtractOut(CreateProcedureStr3)
1709 else
1710 ExtractOut(CreateProcedureStr2);
1711
1712 {SQL Security added in Firebird 4}
1713 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION13 then
1714 begin
1715 qryProcSecurity.SQL.Text := ProcedureSecuritySQL;
1716 qryProcSecurity.Params.ByName('ProcedureName').AsString := ProcName;
1717 qryProcSecurity.ExecQuery;
1718 if not qryProcSecurity.FieldByName('RDB$SQL_SECURITY').IsNull then
1719 ExtractOut(AddSQLSecurity(qryProcSecurity.FieldByName('RDB$SQL_SECURITY')));
1720 end;
1721 ExtractOut(ProcTerm);
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 if not qryProcSecurity.FieldByName('RDB$SQL_SECURITY').IsNull then
1747 ExtractOut(AddSQLSecurity(qryProcSecurity.FieldByName('RDB$SQL_SECURITY')));
1748 end;
1749
1750 ExtractOut(ProcTerm);
1751
1752 end;
1753
1754 pdAlterProc:
1755 begin
1756 ExtractOut(Format('ALTER PROCEDURE %s', [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(ProcTerm);
1763 ExtractOut(SList);
1764 end
1765 else
1766 ExtractOut(CreateProcedureStr2 + ProcTerm);
1767 end;
1768 end;
1769 ExtractOut('');
1770 if IncludeGrants then
1771 ShowGrantsTo(ProcName,obj_procedure,ProcTerm);
1772 qryProcedures.Next;
1773 end;
1774 qryProcedures.Close;
1775
1776 if not Header then
1777 begin
1778 ExtractOut(Format('SET TERM %s%s', [Term, ProcTerm]));
1779 ExtractOut('COMMIT WORK;');
1780 ExtractOut('SET AUTODDL ON;');
1781 end;
1782 ExtractOut(Comments);
1783 finally
1784 qryProcedures.Free;
1785 qryProcSecurity.Free;
1786 SList.Free;
1787 Comments.Free;
1788 end;
1789 end;
1790
1791 { ListAllTables
1792 Functional description
1793 Extract the names of all user tables from
1794 rdb$relations. Filter SQL tables by
1795 security class after we fetch them
1796 Parameters: flag -- 0, get all tables }
1797
1798 procedure TIBExtract.ListAllTables(flag: Boolean);
1799 const
1800 TableSQL =
1801 'SELECT * FROM RDB$RELATIONS ' +
1802 'WHERE ' +
1803 ' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' +
1804 ' RDB$VIEW_BLR IS NULL ' +
1805 'ORDER BY RDB$RELATION_NAME';
1806
1807 var
1808 qryTables : TIBSQL;
1809 begin
1810 { This version of cursor gets only sql tables identified by security class
1811 and misses views, getting only null view_source }
1812
1813 qryTables := TIBSQL.Create(FDatabase);
1814 try
1815 qryTables.SQL.Text := TableSQL;
1816 qryTables.ExecQuery;
1817 while not qryTables.Eof do
1818 begin
1819 if ((qryTables.FieldByName('RDB$FLAGS').AsInteger <> 1) and
1820 (not Flag)) then
1821 continue;
1822 if flag or (Pos('SQL$', qryTables.FieldByName('RDB$SECURITY_CLASS').AsString) <> 1) then
1823 ExtractListTable(qryTables.FieldByName('RDB$RELATION_NAME').AsString,
1824 '', false);
1825
1826 qryTables.Next;
1827 end;
1828 finally
1829 qryTables.Free;
1830 end;
1831 end;
1832
1833 { ListAllTriggers
1834 Functional description
1835 Lists triggers in general on non-system
1836 tables with sql source only. }
1837
1838 procedure TIBExtract.ListTriggers(ObjectName: String; ExtractTypes: TExtractTypes
1839 );
1840 const
1841 { Query gets the trigger info for non-system triggers with
1842 source that are not part of an SQL constraint }
1843
1844 TriggerSQL =
1845 'SELECT * FROM RDB$TRIGGERS TRG Left Outer JOIN RDB$RELATIONS REL ON ' +
1846 ' TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME ' +
1847 'WHERE ' +
1848 ' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' +
1849 ' NOT EXISTS (SELECT * FROM RDB$CHECK_CONSTRAINTS CHK WHERE ' +
1850 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME) ' +
1851 'ORDER BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, ' +
1852 ' TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME';
1853
1854 TriggerNameSQL =
1855 'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$RELATIONS REL ON ' +
1856 ' TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME ' +
1857 'WHERE ' +
1858 ' REL.RDB$RELATION_NAME = :TableName AND ' +
1859 ' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' +
1860 ' NOT EXISTS (SELECT * FROM RDB$CHECK_CONSTRAINTS CHK WHERE ' +
1861 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME) ' +
1862 'ORDER BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, ' +
1863 ' TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME';
1864
1865 TriggerByNameSQL =
1866 'SELECT * FROM RDB$TRIGGERS TRG Left Outer JOIN RDB$RELATIONS REL ON ' +
1867 ' TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME ' +
1868 'WHERE ' +
1869 ' TRG.RDB$TRIGGER_NAME = :TriggerName AND ' +
1870 ' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' +
1871 ' NOT EXISTS (SELECT * FROM RDB$CHECK_CONSTRAINTS CHK WHERE ' +
1872 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME) ' +
1873 'ORDER BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, ' +
1874 ' TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME';
1875
1876 TriggerSecuritySQL = 'Select RDB$SQL_SECURITY From RDB$TRIGGERS Where RDB$TRIGGER_NAME = :TriggerName';
1877
1878 var
1879 Header : Boolean;
1880 TriggerName, RelationName, InActive: String;
1881 TriggerHeader: string;
1882 qryTriggers : TIBSQL;
1883 qryTriggerSec: TIBSQL;
1884 SList : TStrings;
1885 Comments: TStrings;
1886 begin
1887 Header := true;
1888 if [etTable,etTrigger ] * ExtractTypes <> [] then
1889 ExtractTypes -= [etDatabaseTriggers,etDDLTriggers];
1890 SList := TStringList.Create;
1891 Comments := TStringList.Create;
1892 qryTriggers := TIBSQL.Create(FDatabase);
1893 qryTriggerSec := TIBSQL.Create(FDatabase);
1894 try
1895 if ObjectName = '' then
1896 qryTriggers.SQL.Text := TriggerSQL
1897 else
1898 begin
1899 if etTable in ExtractTypes then
1900 begin
1901 qryTriggers.SQL.Text := TriggerNameSQL;
1902 qryTriggers.Params.ByName('TableName').AsString := ObjectName;
1903 end
1904 else
1905 begin
1906 qryTriggers.SQL.Text := TriggerByNameSQL;
1907 qryTriggers.Params.ByName('TriggerName').AsString := ObjectName;
1908 end;
1909 end;
1910 qryTriggers.ExecQuery;
1911 while not qryTriggers.Eof do
1912 begin
1913 AddComment(qryTriggers,ctTrigger,Comments);
1914 SList.Clear;
1915 if Header then
1916 begin
1917 ExtractOut(Format('SET TERM %s%s%s', [Procterm, Term, LineEnding]));
1918 ExtractOut(Format('%s/* Triggers only will work for SQL triggers */%s',
1919 [LineEnding, LineEnding]));
1920 Header := false;
1921 end;
1922 TriggerName := qryTriggers.FieldByName('RDB$TRIGGER_NAME').AsString;
1923 RelationName := qryTriggers.FieldByName('RDB$RELATION_NAME').AsString;
1924 if qryTriggers.FieldByName('RDB$TRIGGER_INACTIVE').IsNull then
1925 InActive := 'INACTIVE'
1926 else
1927 if qryTriggers.FieldByName('RDB$TRIGGER_INACTIVE').AsInteger = 1 then
1928 InActive := 'INACTIVE'
1929 else
1930 InActive := 'ACTIVE';
1931
1932 if (ExtractTypes * [etDatabaseTriggers,etDDLTriggers] = []) or
1933 ((etDatabaseTriggers in ExtractTypes) and (qryTriggers.FieldByName('RDB$TRIGGER_TYPE').AsInt64 and $2000 <> 0)) or
1934 ((etDDLTriggers in ExtractTypes) and (qryTriggers.FieldByName('RDB$TRIGGER_TYPE').AsInt64 and $4000 <> 0))
1935 then
1936 begin
1937 if qryTriggers.FieldByName('RDB$FLAGS').AsInteger <> 1 then
1938 SList.Add('/* ');
1939
1940 {Database or Transaction trigger}
1941 if RelationName <> '' then
1942 SList.Add(Format('CREATE TRIGGER %s FOR %s%s%s %s POSITION %d',
1943 [QuoteIdentifier( TriggerName), QuoteIdentifier( RelationName),
1944 LineEnding, InActive,
1945 GetTriggerType(qryTriggers.FieldByName('RDB$TRIGGER_TYPE').AsInt64),
1946 qryTriggers.FieldByName('RDB$TRIGGER_SEQUENCE').AsInteger]))
1947 else
1948 SList.Add(Format('CREATE TRIGGER %s%s%s %s POSITION %d',
1949 [QuoteIdentifier( TriggerName),
1950 LineEnding, InActive,
1951 GetTriggerType(qryTriggers.FieldByName('RDB$TRIGGER_TYPE').AsInt64),
1952 qryTriggers.FieldByName('RDB$TRIGGER_SEQUENCE').AsInteger]));
1953
1954 {SQL Security added in Firebird 4}
1955 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION13 then
1956 begin
1957 qryTriggerSec.SQL.Text := TriggerSecuritySQL;
1958 qryTriggerSec.Params.ByName('TriggerName').AsString := TriggerName;
1959 qryTriggerSec.ExecQuery;
1960 if not qryTriggerSec.FieldByName('RDB$SQL_SECURITY').IsNull then
1961 SList.Add(AddSQLSecurity(qryTriggerSec.FieldByName('RDB$SQL_SECURITY')));
1962 end;
1963
1964 if not qryTriggers.FieldByName('RDB$TRIGGER_SOURCE').IsNull then
1965 SList.Add(qryTriggers.FieldByName('RDB$TRIGGER_SOURCE').AsString)
1966 else
1967 SList.Add('AS BEGIN EXIT; END');
1968 SList.Add(ProcTerm);
1969 SList.Add('');
1970 if qryTriggers.FieldByName('RDB$FLAGS').AsInteger <> 1 then
1971 SList.Add(' */');
1972 ExtractOut(SList);
1973 if etGrant in ExtractTypes then
1974 ShowGrantsTo(TriggerName,obj_trigger,ProcTerm);
1975 end;
1976 qryTriggers.Next;
1977 end;
1978 if not Header then
1979 begin
1980 ExtractOut('COMMIT WORK' + ProcTerm);
1981 ExtractOut('SET TERM ' + Term + ProcTerm);
1982 end;
1983 ExtractOut(Comments);
1984 finally
1985 Comments.Free;
1986 qryTriggers.Free;
1987 qryTriggerSec.Free;
1988 SList.Free;
1989 end;
1990 end;
1991
1992 { ListCheck
1993 Functional description
1994 List check constraints for all objects to allow forward references }
1995
1996 procedure TIBExtract.ListCheck(ObjectName : String; ExtractType : TExtractType);
1997 const
1998 { Query gets the check clauses for triggers stored for check constraints }
1999 CheckSQL =
2000 'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$CHECK_CONSTRAINTS CHK ON ' +
2001 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME ' +
2002 'WHERE ' +
2003 ' TRG.RDB$TRIGGER_TYPE = 1 AND ' +
2004 ' EXISTS (SELECT RDB$CONSTRAINT_NAME FROM RDB$RELATION_CONSTRAINTS RELC WHERE ' +
2005 ' CHK.RDB$CONSTRAINT_NAME = RELC.RDB$CONSTRAINT_NAME) ' +
2006 'ORDER BY CHK.RDB$CONSTRAINT_NAME';
2007
2008 CheckNameSQL =
2009 'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$CHECK_CONSTRAINTS CHK ON ' +
2010 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME ' +
2011 'WHERE ' +
2012 ' TRG.RDB$RELATION_NAME = :TableName AND ' +
2013 ' TRG.RDB$TRIGGER_TYPE = 1 AND ' +
2014 ' EXISTS (SELECT RDB$CONSTRAINT_NAME FROM RDB$RELATION_CONSTRAINTS RELC WHERE ' +
2015 ' CHK.RDB$CONSTRAINT_NAME = RELC.RDB$CONSTRAINT_NAME) ' +
2016 'ORDER BY CHK.RDB$CONSTRAINT_NAME';
2017
2018 CheckByNameSQL =
2019 'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$CHECK_CONSTRAINTS CHK ON ' +
2020 ' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME ' +
2021 'WHERE ' +
2022 ' TRG.RDB$TRIGGER_NAME = :TriggerName AND ' +
2023 ' TRG.RDB$TRIGGER_TYPE = 1 AND ' +
2024 ' EXISTS (SELECT RDB$CONSTRAINT_NAME FROM RDB$RELATION_CONSTRAINTS RELC WHERE ' +
2025 ' CHK.RDB$CONSTRAINT_NAME = RELC.RDB$CONSTRAINT_NAME) ' +
2026 'ORDER BY CHK.RDB$CONSTRAINT_NAME';
2027
2028 var
2029 qryChecks : TIBSQL;
2030 SList : TStrings;
2031 RelationName : String;
2032 begin
2033 qryChecks := TIBSQL.Create(FDatabase);
2034 SList := TStringList.Create;
2035 try
2036 if ObjectName = '' then
2037 qryChecks.SQL.Text := CheckSQL
2038 else
2039 if ExtractType = etTable then
2040 begin
2041 qryChecks.SQL.Text := CheckNameSQL;
2042 qryChecks.Params.ByName('TableName').AsString := ObjectName;
2043 end
2044 else
2045 begin
2046 qryChecks.SQL.Text := CheckByNameSQL;
2047 qryChecks.Params.ByName('TriggerName').AsString := ObjectName;
2048 end;
2049 qryChecks.ExecQuery;
2050 while not qryChecks.Eof do
2051 begin
2052 SList.Clear;
2053 RelationName := qryChecks.FieldByName('RDB$RELATION_NAME').AsString;
2054 SList.Add(Format('ALTER TABLE %s ADD',
2055 [QuoteIdentifier( RelationName)]));
2056 if Pos('INTEG', qryChecks.FieldByName('RDB$CONSTRAINT_NAME').AsString) <> 1 then
2057 SList.Add(Format('%sCONSTRAINT %s ', [TAB,
2058 QuoteIdentifier( qryChecks.FieldByName('RDB$CONSTRAINT_NAME').AsString)]));
2059
2060 if not qryChecks.FieldByName('RDB$TRIGGER_SOURCE').IsNull then
2061 SList.Text := SList.Text + qryChecks.FieldByName('RDB$TRIGGER_SOURCE').AsString;
2062
2063 SList.Strings[SList.Count - 1] := SList.Strings[SList.Count - 1] + (Term) + LineEnding;
2064 ExtractOut(SList);
2065 qryChecks.Next;
2066 end;
2067 finally
2068 qryChecks.Free;
2069 SList.Free;
2070 end;
2071 end;
2072
2073 procedure TIBExtract.ListComments(CommentTypes: TCommentTypes);
2074
2075 procedure DoListComments(cmt: TCommentType);
2076 var qryCmt: TIBSQL;
2077 sql: string;
2078 index: integer;
2079 begin
2080 index := LookupDDLObject(cmt);
2081 if index = -1 then Exit;
2082
2083 qryCmt := TIBSQL.Create(FDatabase);
2084 try
2085 with DDLObjects[index] do
2086 begin
2087 sql := 'Select * From '+ SystemTableName;
2088 if not (cmt in [ctCharacterSet, ctCollation, ctDatabase]) then
2089 begin
2090 if not ShowSystem then
2091 sql += ' Where (RDB$SYSTEM_FLAG is null or RDB$SYSTEM_FLAG = 0)';
2092 if Condition <> '' then
2093 begin
2094 if not ShowSystem then
2095 sql += ' AND ' + Condition
2096 else
2097 sql += ' Where ' + Condition;
2098 end;
2099 end;
2100 sql += ' Order by 1';
2101 end;
2102 qryCmt.SQL.Text := sql;
2103 qryCmt.ExecQuery;
2104 while not qryCmt.Eof do
2105 begin
2106 AddComment(qryCmt,cmt);
2107 qryCmt.Next;
2108 end;
2109 finally
2110 qryCmt.Free;
2111 end;
2112 end;
2113
2114 var cType: TCommentType;
2115 begin
2116 if CommentTypes = [] then
2117 begin
2118 for cType := low(TCommentType) to High(TCommentType) do
2119 DoListComments(cType)
2120 end
2121 else
2122 for cType in CommentTypes do
2123 DoListComments(cType);
2124 end;
2125
2126 { ListCreateDb
2127 Functional description
2128 Print the create database command if requested. At least put
2129 the page size in a comment with the extracted db name }
2130
2131 procedure TIBExtract.ListCreateDb(TargetDb : String);
2132 const
2133 CharInfoSQL =
2134 'SELECT * FROM RDB$DATABASE DBP ' +
2135 'WHERE NOT DBP.RDB$CHARACTER_SET_NAME IS NULL ' +
2136 ' AND DBP.RDB$CHARACTER_SET_NAME <> '' ''';
2137
2138 DBSecuritySQL = 'Select RDB$SQL_SECURITY FROM RDB$DATABASE';
2139
2140 FilesSQL =
2141 'select * from RDB$FILES ' +
2142 'order BY RDB$SHADOW_NUMBER, RDB$FILE_SEQUENCE';
2143
2144 LogsSQL =
2145 'SELECT * FROM RDB$LOG_FILES ' +
2146 'ORDER BY RDB$FILE_FLAGS, RDB$FILE_SEQUENCE';
2147
2148 DBSQLSecurity_SQL = 'ALTER DATABASE SET DEFAULT%s;';
2149
2150 var
2151 NoDb, First, FirstFile, HasWal, SetUsed : Boolean;
2152 Buffer : String;
2153 qryDB : TIBSQL;
2154 FileFlags, FileLength, FileSequence, FileStart : Integer;
2155 Comments: TStrings;
2156
2157 function GetLongDatabaseInfo(DatabaseInfoCommand: Integer): LongInt;
2158 begin
2159 with Database.Attachment.GetDBInformation([DatabaseInfoCommand]) do
2160 if (Count > 0) and (Items[0].GetItemType = DatabaseInfoCommand) then
2161 Result := Items[0].AsInteger
2162 else
2163 IBError(ibxeUnexpectedDatabaseInfoResp,[nil]);
2164 end;
2165
2166 begin
2167 NoDb := FALSE;
2168 First := TRUE;
2169 FirstFile := TRUE;
2170 HasWal := FALSE;
2171 SetUsed := FALSE;
2172 Buffer := '';
2173 if TargetDb = '' then
2174 begin
2175 Buffer := '/* ';
2176 TargetDb := FDatabase.DatabaseName;
2177 NoDb := true;
2178 end;
2179 Buffer := Buffer + 'CREATE DATABASE ' + QuotedStr(TargetDb) + ' PAGE_SIZE ' +
2180 IntToStr(FDatabaseInfo.PageSize) + LineEnding;
2181 ExtractOut(Buffer);
2182 Buffer := '';
2183
2184 Comments := TStringList.Create;
2185 qryDB := TIBSQL.Create(FDatabase);
2186 try
2187 qryDB.SQL.Text := CharInfoSQL;
2188 qryDB.ExecQuery;
2189
2190 if not qryDB.EOF then
2191 begin
2192 FDefaultCharSetName := trim(qryDB.FieldByName('RDB$CHARACTER_SET_NAME').AsString);
2193 Buffer := Format(' DEFAULT CHARACTER SET %s',
2194 [FDefaultCharSetName]);
2195 end;
2196 if NoDB then
2197 Buffer := Buffer + Term + ' */'
2198 else
2199 Buffer := Buffer + Term;
2200 ExtractOut(Buffer);
2201 AddComment(qryDB,ctDatabase,Comments);
2202 qryDB.Close;
2203 {List secondary files and shadows as
2204 alter db and create shadow in comment}
2205 qryDB.SQL.Text := FilesSQL;
2206 qryDB.ExecQuery;
2207 while not qryDB.Eof do
2208 begin
2209 if First then
2210 begin
2211 ExtractOut(LineEnding + '/* Add secondary files in comments ');
2212 First := false;
2213 end; //end_if
2214
2215 if qryDB.FieldByName('RDB$FILE_FLAGS').IsNull then
2216 FileFlags := 0
2217 else
2218 FileFlags := qryDB.FieldByName('RDB$FILE_FLAGS').AsInteger;
2219 if qryDB.FieldByName('RDB$FILE_LENGTH').IsNull then
2220 FileLength := 0
2221 else
2222 FileLength := qryDB.FieldByName('RDB$FILE_LENGTH').AsInteger;
2223 if qryDB.FieldByName('RDB$FILE_SEQUENCE').IsNull then
2224 FileSequence := 0
2225 else
2226 FileSequence := qryDB.FieldByName('RDB$FILE_SEQUENCE').AsInteger;
2227 if qryDB.FieldByName('RDB$FILE_START').IsNull then
2228 FileStart := 0
2229 else
2230 FileStart := qryDB.FieldByName('RDB$FILE_START').AsInteger;
2231
2232 { Pure secondary files }
2233 if FileFlags = 0 then
2234 begin
2235 Buffer := Format('%sALTER DATABASE ADD FILE ''%s''',
2236 [LineEnding, qryDB.FieldByName('RDB$FILE_NAME').AsString]);
2237 if FileStart <> 0 then
2238 Buffer := Buffer + Format(' STARTING %d', [FileStart]);
2239 if FileLength <> 0 then
2240 Buffer := Buffer + Format(' LENGTH %d', [FileLength]);
2241 ExtractOut(Buffer);
2242 end; //end_if
2243 if (FileFlags and FILE_cache) <> 0 then
2244 ExtractOut(Format('%sALTER DATABASE ADD CACHE ''%s'' LENGTH %d',
2245 [LineEnding, qryDB.FieldByName('RDB$FILE_NAME').AsString, FileLength]));
2246
2247 Buffer := '';
2248 if (FileFlags and FILE_shadow) <> 0 then
2249 begin
2250 if FileSequence <> 0 then
2251 Buffer := Format('%sFILE ''%s''',
2252 [TAB, qryDB.FieldByName('RDB$FILE_NAME').AsString])
2253 else
2254 begin
2255 Buffer := Format('%sCREATE SHADOW %d ''%s'' ',
2256 [LineEnding, qryDB.FieldByName('RDB$SHADOW_NUMBER').AsInteger,
2257 qryDB.FieldByName('RDB$FILE_NAME').AsString]);
2258 if (FileFlags and FILE_inactive) <> 0 then
2259 Buffer := Buffer + 'INACTIVE ';
2260 if (FileFlags and FILE_manual) <> 0 then
2261 Buffer := Buffer + 'MANUAL '
2262 else
2263 Buffer := Buffer + 'AUTO ';
2264 if (FileFlags and FILE_conditional) <> 0 then
2265 Buffer := Buffer + 'CONDITIONAL ';
2266 end; //end_else
2267 if FileLength <> 0 then
2268 Buffer := Buffer + Format('LENGTH %d ', [FileLength]);
2269 if FileStart <> 0 then
2270 Buffer := Buffer + Format('STARTING %d ', [FileStart]);
2271 ExtractOut(Buffer);
2272 end; //end_if
2273 qryDB.Next;
2274 end;
2275 qryDB.Close;
2276
2277 qryDB.SQL.Text := LogsSQL;
2278 qryDB.ExecQuery;
2279 while not qryDB.Eof do
2280 begin
2281
2282 if qryDB.FieldByName('RDB$FILE_FLAGS').IsNull then
2283 FileFlags := 0
2284 else
2285 FileFlags := qryDB.FieldByName('RDB$FILE_FLAGS').AsInteger;
2286 if qryDB.FieldByName('RDB$FILE_LENGTH').IsNull then
2287 FileLength := 0
2288 else
2289 FileLength := qryDB.FieldByName('RDB$FILE_LENGTH').AsInteger;
2290
2291 Buffer := '';
2292 HasWal := true;
2293 if First then
2294 begin
2295 if NoDB then
2296 Buffer := '/* ';
2297 Buffer := Buffer + LineEnding + 'ALTER DATABASE ADD ';
2298 First := false;
2299 end; //end_if
2300 if FirstFile then
2301 Buffer := Buffer + 'LOGFILE ';
2302 { Overflow files also have the serial bit set }
2303 if (FileFlags and LOG_default) = 0 then
2304 begin
2305 if (FileFlags and LOG_overflow) <> 0 then
2306 Buffer := Buffer + Format(')%s OVERFLOW ''%s''',
2307 [LineEnding, qryDB.FieldByName('RDB$FILE_NAME').AsString])
2308 else
2309 if (FileFlags and LOG_serial) <> 0 then
2310 Buffer := Buffer + Format('%s BASE_NAME ''%s''',
2311 [LineEnding, qryDB.FieldByName('RDB$FILE_NAME').AsString])
2312 { Since we are fetching order by FILE_FLAGS, the LOG_0verflow will
2313 be last. It will only appear if there were named round robin,
2314 so we must close the parens first }
2315
2316 { We have round robin and overflow file specifications }
2317 else
2318 begin
2319 if FirstFile then
2320 Buffer := Buffer + '('
2321 else
2322 Buffer := Buffer + Format(',%s ', [LineEnding]);
2323 FirstFile := false;
2324
2325 Buffer := Buffer + Format('''%s''', [qryDB.FieldByName('RDB$FILE_NAME').AsString]);
2326 end; //end_else
2327 end;
2328 { Any file can have a length }
2329 if FileLength <> 0 then
2330 Buffer := Buffer + Format(' SIZE %d ', [FileLength]);
2331 ExtractOut(Buffer);
2332 qryDB.Next;
2333 end;
2334 qryDB.Close;
2335 Buffer := '';
2336 if HasWal then
2337 begin
2338 Buffer := Buffer + PrintSet(SetUsed);
2339 Buffer := Buffer + Format('NUM_LOG_BUFFERS = %d',
2340 [GetLongDatabaseInfo(isc_info_num_wal_buffers)]);
2341 Buffer := Buffer + PrintSet(SetUsed);
2342 Buffer := Buffer + Format('LOG_BUFFER_SIZE = %d',
2343 [GetLongDatabaseInfo(isc_info_wal_buffer_size)]);
2344 Buffer := Buffer + PrintSet(SetUsed);
2345 Buffer := Buffer + Format('GROUP_COMMIT_WAIT_TIME = %d',
2346 [GetLongDatabaseInfo(isc_info_wal_grpc_wait_usecs)]);
2347 Buffer := Buffer + PrintSet(SetUsed);
2348 Buffer := Buffer + Format('CHECK_POINT_LENGTH = %d',
2349 [GetLongDatabaseInfo(isc_info_wal_ckpt_length)]);
2350 ExtractOut(Buffer);
2351
2352 end;
2353
2354 {SQL Security added in Firebird 4}
2355 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION13 then
2356 begin
2357 qryDB.SQL.Text := DBSecuritySQL;
2358 qryDB.ExecQuery;
2359 if not qryDB.FieldByName('RDB$SQL_SECURITY').IsNull then
2360 ExtractOut(Format(DBSQLSecurity_SQL,[AddSQLSecurity(qryDB.FieldByName('RDB$SQL_SECURITY'))]));
2361 end;
2362
2363 if not First then
2364 begin
2365 if NoDB then
2366 ExtractOut(Format('%s */%s', [LineEnding, LineEnding]))
2367 else
2368 ExtractOut(Format('%s%s%s', [Term, LineEnding, LineEnding]));
2369 end;
2370
2371 ExtractOut(Comments);
2372 finally
2373 qryDB.Free;
2374 Comments.Free;
2375 end;
2376
2377 (*
2378 *)
2379 end;
2380
2381 { ListDomainTable
2382 Functional description
2383 List domains as identified by fields with any constraints on them
2384 for the named table
2385
2386 Parameters: table_name == only extract domains for this table }
2387
2388 procedure TIBExtract.ListDomains(DomainDDLType: TDomainDDLType;
2389 ObjectName: String; ExtractType: TExtractType);
2390 const
2391 DomainSQL =
2392 'SELECT distinct fld.* FROM RDB$FIELDS FLD JOIN RDB$RELATION_FIELDS RFR ON ' +
2393 ' RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME ' +
2394 'WHERE RFR.RDB$RELATION_NAME = :TABLE_NAME ' +
2395 'ORDER BY FLD.RDB$FIELD_NAME';
2396
2397 DomainByNameSQL =
2398 'SELECT * FROM RDB$FIELDS FLD ' +
2399 'WHERE FLD.RDB$FIELD_NAME = :DomainName ' +
2400 'ORDER BY FLD.RDB$FIELD_NAME';
2401
2402 AllDomainSQL =
2403 'select * from RDB$FIELDS ' +
2404 'where RDB$SYSTEM_FLAG <> 1 ' +
2405 'order BY RDB$FIELD_NAME';
2406
2407 var
2408 First : Boolean;
2409 qryDomains : TIBSQL;
2410 FieldName, Line : String;
2411 begin
2412 First := true;
2413 qryDomains := TIBSQL.Create(FDatabase);
2414 try
2415 if ObjectName <> '' then
2416 begin
2417 if ExtractType = etTable then
2418 begin
2419 qryDomains.SQL.Text := DomainSQL;
2420 qryDomains.Params.ByName('table_name').AsString := ObjectName;
2421 end
2422 else
2423 begin
2424 qryDomains.SQL.Text := DomainByNameSQL;
2425 qryDomains.Params.ByName('DomainName').AsString := ObjectName;
2426 end;
2427 end
2428 else
2429 qryDomains.SQL.Text := AllDomainSQL;
2430
2431 qryDomains.ExecQuery;
2432 while not qryDomains.Eof do
2433 begin
2434 FieldName := trim(qryDomains.FieldByName('RDB$FIELD_NAME').AsString);
2435 { Skip over artifical domains }
2436 if (Pos('RDB$',FieldName) = 1) and
2437 (FieldName[5] in ['0'..'9']) and
2438 (qryDomains.FieldByName('RDB$SYSTEM_FLAG').AsInteger <> 1) then
2439 begin
2440 qryDomains.Next;
2441 continue;
2442 end;
2443
2444 if First then
2445 begin
2446 ExtractOut('');
2447 if DomainDDLType in [dtCreateDomain,dtCreateNoCheckConstraint] then
2448 ExtractOut('/* Domain definitions */')
2449 else
2450 ExtractOut('/* Add Domain Check Constraints */');
2451 ExtractOut('');
2452 First := false;
2453 end;
2454
2455 Line := '';
2456 if DomainDDLType in [dtCreateDomain,dtCreateNoCheckConstraint] then
2457 begin
2458 Line := Format('CREATE DOMAIN %s AS ', [FieldName]) +
2459 GetFieldType(qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger,
2460 qryDomains.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger,
2461 qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger,
2462 qryDomains.FieldByName('RDB$FIELD_PRECISION').AsInteger,
2463 qryDomains.FieldByName('RDB$FIELD_LENGTH').AsInteger,
2464 qryDomains.FieldByName('RDB$CHARACTER_SET_ID').IsNull,
2465 false,
2466 qryDomains.FieldByName('RDB$CHARACTER_SET_ID').AsInteger,
2467 qryDomains.FieldByName('RDB$CHARACTER_LENGTH').AsInteger,
2468 qryDomains.FieldByName('RDB$SEGMENT_LENGTH').AsInteger,
2469 not qryDomains.FieldByName('RDB$DIMENSIONS').IsNull and
2470 (qryDomains.FieldByName('RDB$DIMENSIONS').AsInteger <> 0),
2471 FieldName);
2472
2473 if not qryDomains.FieldByName('RDB$DEFAULT_SOURCE').IsNull then
2474 Line := Line + Format('%s%s %s', [LineEnding, TAB,
2475 qryDomains.FieldByName('RDB$DEFAULT_SOURCE').AsString]);
2476
2477 if qryDomains.FieldByName('RDB$NULL_FLAG').AsInteger = 1 then
2478 Line := Line + ' NOT NULL';
2479 end;
2480
2481 if not qryDomains.FieldByName('RDB$VALIDATION_SOURCE').IsNull then
2482 begin
2483 if DomainDDLType = dtAddCheckConstraint then
2484 Line := Format('ALTER DOMAIN %s ADD CONSTRAINT',[FieldName]);
2485
2486 if DomainDDLType in [dtCreateDomain,dtAddCheckConstraint] then
2487 begin
2488 if Pos('CHECK', AnsiUpperCase(qryDomains.FieldByName('RDB$VALIDATION_SOURCE').AsString)) = 1 then
2489 Line := Line + Format('%s%s %s', [LineEnding, TAB,
2490 trim(qryDomains.FieldByName('RDB$VALIDATION_SOURCE').AsString)])
2491 else
2492 Line := Line + Format('%s%s /* %s */', [LineEnding, TAB,
2493 trim(qryDomains.FieldByName('RDB$VALIDATION_SOURCE').AsString)]);
2494 end;
2495 end;
2496
2497 { Show the collation order if one has been specified. If the collation
2498 order is the default for the character set being used, then no collation
2499 order will be shown ( because it isn't needed ).
2500
2501 If the collation id is 0, then the default for the character set is
2502 being used so there is no need to retrieve the collation information.}
2503
2504 if (DomainDDLType in [dtCreateDomain,dtCreateNoCheckConstraint]) and
2505 (not qryDomains.FieldByName('RDB$COLLATION_ID').IsNull) and
2506 (qryDomains.FieldByName('RDB$COLLATION_ID').AsInteger <> 0) then
2507 Line := Line + GetCollationName(qryDomains.FieldByName('RDB$CHARACTER_SET_ID').AsInteger,
2508 qryDomains.FieldByName('RDB$COLLATION_ID').AsInteger);
2509 if Line <> '' then
2510 Line := Line + Term;
2511 ExtractOut(Line);
2512 if (DomainDDLType in [dtCreateDomain,dtCreateNoCheckConstraint]) then
2513 AddComment(qryDomains,ctDomain);
2514 qryDomains.Next;
2515 end;
2516 finally
2517 qryDomains.Free;
2518 end;
2519 end;
2520
2521 { ListException
2522 Functional description
2523 List all exceptions defined in the database
2524
2525 Parameters: none }
2526
2527 procedure TIBExtract.ListException(ExceptionName : String = '');
2528 const
2529 ExceptionSQL =
2530 'select * from RDB$EXCEPTIONS ' +
2531 'ORDER BY RDB$EXCEPTION_NAME';
2532
2533 ExceptionNameSQL =
2534 'select * from RDB$EXCEPTIONS ' +
2535 'WHERE RDB$EXCEPTION_NAME = :ExceptionName ' +
2536 'ORDER BY RDB$EXCEPTION_NAME';
2537
2538 var
2539 First : Boolean;
2540 qryException : TIBSQL;
2541 begin
2542 First := true;
2543 qryException := TIBSQL.Create(FDatabase);
2544 try
2545 if ExceptionName = '' then
2546 qryException.SQL.Text := ExceptionSQL
2547 else
2548 begin
2549 qryException.SQL.Text := ExceptionNameSQL;
2550 qryException.Params.ByName('ExceptionName').AsString := ExceptionName;
2551 end;
2552
2553 qryException.ExecQuery;
2554 while not qryException.Eof do
2555 begin
2556 if First then
2557 begin
2558 ExtractOut('');
2559 ExtractOut('/* Exceptions */');
2560 ExtractOut('');
2561 First := false;
2562 end; //end_if
2563
2564 ExtractOut(Format('CREATE EXCEPTION %s %s%s',
2565 [QuoteIdentifier( qryException.FieldByName('RDB$EXCEPTION_NAME').AsString),
2566 QuotedStr(qryException.FieldByName('RDB$MESSAGE').AsString), Term]));
2567 AddComment(qryException,ctException);
2568 qryException.Next;
2569 end;
2570 finally
2571 qryException.Free;
2572 end;
2573 end;
2574
2575 { ListFilters
2576
2577 Functional description
2578 List all blob filters
2579
2580 Parameters: none
2581 Results in
2582 DECLARE FILTER <fname> INPUT_TYPE <blob_sub_type> OUTPUT_TYPE <blob_subtype>
2583 ENTRY_POINT <string> MODULE_NAME <string> }
2584
2585 procedure TIBExtract.ListFilters(FilterName : String = '');
2586 const
2587 FiltersSQL =
2588 'SELECT * FROM RDB$FILTERS ' +
2589 'ORDER BY RDB$FUNCTION_NAME';
2590 FilterNameSQL =
2591 'SELECT * FROM RDB$FILTERS ' +
2592 'WHERE RDB$FUNCTION_NAME = :FunctionName ' +
2593 'ORDER BY RDB$FUNCTION_NAME';
2594
2595 var
2596 First : Boolean;
2597 qryFilters : TIBSQL;
2598 begin
2599 First := true;
2600 qryFilters := TIBSQL.Create(FDatabase);
2601 try
2602 if FilterName = '' then
2603 qryFilters.SQL.Text := FiltersSQL
2604 else
2605 begin
2606 qryFilters.SQL.Text := FilterNameSQL;
2607 qryFilters.Params.ByName('FunctionName').AsString := FilterName;
2608 end;
2609 qryFilters.ExecQuery;
2610 while not qryFilters.Eof do
2611 begin
2612 if First then
2613 begin
2614 ExtractOut('');
2615 ExtractOut('/* BLOB Filter declarations */');
2616 ExtractOut('');
2617 First := false;
2618 end; //end_if
2619
2620 ExtractOut(Format('DECLARE FILTER %s INPUT_TYPE %d OUTPUT_TYPE %d',
2621 [qryFilters.FieldByName('RDB$FUNCTION_NAME').AsString,
2622 qryFilters.FieldByName('RDB$INPUT_SUB_TYPE').AsInteger,
2623 qryFilters.FieldByName('RDB$OUTPUT_SUB_TYPE').AsInteger]));
2624 ExtractOut(Format('%sENTRY_POINT ''%s'' MODULE_NAME ''%s''%s%',
2625 [TAB, qryFilters.FieldByName('RDB$ENTRYPOINT').AsString,
2626 qryFilters.FieldByName('RDB$MODULE_NAME').AsString, Term]));
2627 ExtractOut('');
2628 AddComment(qryFilters,ctFilter);
2629 qryFilters.Next;
2630 end;
2631
2632 finally
2633 qryFilters.Free;
2634 end;
2635 end;
2636
2637 { ListForeign
2638 Functional description
2639 List all foreign key constraints and alter the tables }
2640
2641 procedure TIBExtract.ListForeign(ObjectName : String; ExtractType : TExtractType);
2642 const
2643 { Static queries for obtaining foreign constraints, where RELC1 is the
2644 foreign key constraints, RELC2 is the primary key lookup and REFC
2645 is the join table }
2646 ForeignSQL =
2647 'SELECT REFC.RDB$UPDATE_RULE REFC_UPDATE_RULE, REFC.RDB$DELETE_RULE REFC_DELETE_RULE, ' +
2648 ' RELC1.RDB$RELATION_NAME RELC1_RELATION_NAME, RELC2.RDB$RELATION_NAME RELC2_RELATION_NAME, ' +
2649 ' RELC1.RDB$INDEX_NAME RELC1_INDEX_NAME, RELC1.RDB$CONSTRAINT_NAME RELC1_CONSTRAINT_NAME, ' +
2650 ' RELC2.RDB$INDEX_NAME RELC2_INDEX_NAME ' +
2651 'FROM RDB$REF_CONSTRAINTS REFC, RDB$RELATION_CONSTRAINTS RELC1, ' +
2652 ' RDB$RELATION_CONSTRAINTS RELC2 ' +
2653 'WHERE ' +
2654 ' RELC1.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' AND ' +
2655 ' REFC.RDB$CONST_NAME_UQ = RELC2.RDB$CONSTRAINT_NAME AND ' +
2656 ' REFC.RDB$CONSTRAINT_NAME = RELC1.RDB$CONSTRAINT_NAME AND ' +
2657 ' (RELC2.RDB$CONSTRAINT_TYPE = ''UNIQUE'' OR ' +
2658 ' RELC2.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'') ' +
2659 'ORDER BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME';
2660
2661 ForeignNameSQL =
2662 'SELECT REFC.RDB$UPDATE_RULE REFC_UPDATE_RULE, REFC.RDB$DELETE_RULE REFC_DELETE_RULE, ' +
2663 ' RELC1.RDB$RELATION_NAME RELC1_RELATION_NAME, RELC2.RDB$RELATION_NAME RELC2_RELATION_NAME, ' +
2664 ' RELC1.RDB$INDEX_NAME RELC1_INDEX_NAME, RELC1.RDB$CONSTRAINT_NAME RELC1_CONSTRAINT_NAME, ' +
2665 ' RELC2.RDB$INDEX_NAME RELC2_INDEX_NAME ' +
2666 'FROM RDB$REF_CONSTRAINTS REFC, RDB$RELATION_CONSTRAINTS RELC1, ' +
2667 ' RDB$RELATION_CONSTRAINTS RELC2 ' +
2668 'WHERE ' +
2669 ' RELC1.RDB$RELATION_NAME = :TableName AND ' +
2670 ' RELC1.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' AND ' +
2671 ' REFC.RDB$CONST_NAME_UQ = RELC2.RDB$CONSTRAINT_NAME AND ' +
2672 ' REFC.RDB$CONSTRAINT_NAME = RELC1.RDB$CONSTRAINT_NAME AND ' +
2673 ' (RELC2.RDB$CONSTRAINT_TYPE = ''UNIQUE'' OR ' +
2674 ' RELC2.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'') ' +
2675 'ORDER BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME';
2676
2677 ForeignByNameSQL =
2678 'SELECT REFC.RDB$UPDATE_RULE REFC_UPDATE_RULE, REFC.RDB$DELETE_RULE REFC_DELETE_RULE, ' +
2679 ' RELC1.RDB$RELATION_NAME RELC1_RELATION_NAME, RELC2.RDB$RELATION_NAME RELC2_RELATION_NAME, ' +
2680 ' RELC1.RDB$INDEX_NAME RELC1_INDEX_NAME, RELC1.RDB$CONSTRAINT_NAME RELC1_CONSTRAINT_NAME, ' +
2681 ' RELC2.RDB$INDEX_NAME RELC2_INDEX_NAME ' +
2682 'FROM RDB$REF_CONSTRAINTS REFC, RDB$RELATION_CONSTRAINTS RELC1, ' +
2683 ' RDB$RELATION_CONSTRAINTS RELC2 ' +
2684 'WHERE ' +
2685 ' RELC1.RDB$CONSTRAINT_NAME = :ConstraintName AND ' +
2686 ' RELC1.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' AND ' +
2687 ' REFC.RDB$CONST_NAME_UQ = RELC2.RDB$CONSTRAINT_NAME AND ' +
2688 ' REFC.RDB$CONSTRAINT_NAME = RELC1.RDB$CONSTRAINT_NAME AND ' +
2689 ' (RELC2.RDB$CONSTRAINT_TYPE = ''UNIQUE'' OR ' +
2690 ' RELC2.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'') ' +
2691 'ORDER BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME';
2692
2693 var
2694 qryForeign : TIBSQL;
2695 Line : String;
2696
2697 begin
2698 qryForeign := TIBSQL.Create(FDatabase);
2699 try
2700 if ObjectName = '' then
2701 qryForeign.SQL.Text := ForeignSQL
2702 else
2703 begin
2704 if ExtractType = etTable then
2705 begin
2706 qryForeign.SQL.Text := ForeignNameSQL;
2707 qryForeign.Params.ByName('TableName').AsString := ObjectName;
2708 end
2709 else
2710 begin
2711 qryForeign.SQL.Text := ForeignByNameSQL;
2712 qryForeign.Params.ByName('ConstraintName').AsString := ObjectName;
2713 end;
2714 end;
2715 qryForeign.ExecQuery;
2716 while not qryForeign.Eof do
2717 begin
2718 Line := Format('ALTER TABLE %s ADD ', [QuoteIdentifier(
2719 qryForeign.FieldByName('RELC1_RELATION_NAME').AsString)]);
2720
2721 { If the name of the constraint is not INTEG..., print it.
2722 INTEG... are internally generated names. }
2723 if (not qryForeign.FieldByName('RELC1_CONSTRAINT_NAME').IsNull) and
2724 ( Pos('INTEG', qryForeign.FieldByName('RELC1_CONSTRAINT_NAME').AsString) <> 1) then
2725 Line := Line + Format('CONSTRAINT %s ', [QuoteIdentifier(
2726 Trim(qryForeign.FieldByName('RELC1_CONSTRAINT_NAME').AsString))]);
2727
2728 Line := Line + Format('FOREIGN KEY (%s) REFERENCES %s ', [
2729 GetIndexSegments(qryForeign.FieldByName('RELC1_INDEX_NAME').AsString),
2730 Trim(qryForeign.FieldByName('RELC2_RELATION_NAME').AsString)]);
2731
2732 Line := Line + Format('(%s)',
2733 [GetIndexSegments(qryForeign.FieldByName('RELC2_INDEX_NAME').AsString)]);
2734
2735 { Add the referential actions, if any }
2736 if (not qryForeign.FieldByName('REFC_UPDATE_RULE').IsNull) and
2737 (Trim(qryForeign.FieldByName('REFC_UPDATE_RULE').AsString) <> 'RESTRICT') then
2738 Line := Line + Format(' ON UPDATE %s',
2739 [Trim(qryForeign.FieldByName('REFC_UPDATE_RULE').AsString)]);
2740
2741 if (not qryForeign.FieldByName('REFC_DELETE_RULE').IsNull) and
2742 (Trim(qryForeign.FieldByName('REFC_DELETE_RULE').AsString) <> 'RESTRICT') then
2743 Line := Line + Format(' ON DELETE %s',
2744 [Trim(qryForeign.FieldByName('REFC_DELETE_RULE').AsString)]);
2745
2746 Line := Line + Term;
2747 ExtractOut(Line);
2748 qryForeign.Next;
2749 end;
2750 finally
2751 qryForeign.Free;
2752 end;
2753 end;
2754
2755 { ListExternalFunctions
2756
2757 Functional description
2758 List all external functions
2759
2760 Parameters: none
2761 Results in
2762 DECLARE EXTERNAL FUNCTION function_name
2763 CHAR [256] , INTEGER, ....
2764 RETURNS INTEGER BY VALUE
2765 ENTRY_POINT entrypoint MODULE_NAME module; }
2766
2767 procedure TIBExtract.ListExternalFunctions(FunctionName: String);
2768 const
2769 FunctionSQL =
2770 'SELECT * FROM RDB$FUNCTIONS WHERE RDB$SYSTEM_FLAG = 0 ' +
2771 'ORDER BY RDB$FUNCTION_NAME';
2772
2773 FunctionNameSQL =
2774 'SELECT * FROM RDB$FUNCTIONS ' +
2775 'WHERE RDB$FUNCTION_NAME = :FunctionName ' +
2776 'ORDER BY RDB$FUNCTION_NAME';
2777
2778 FunctionArgsSQL =
2779 'SELECT * FROM RDB$FUNCTION_ARGUMENTS ' +
2780 'WHERE ' +
2781 ' :FUNCTION_NAME = RDB$FUNCTION_NAME ' +
2782 'ORDER BY RDB$ARGUMENT_POSITION';
2783
2784 function GetArgumentType(qryFuncArgs: TIBSQL): string;
2785 var FieldType: integer;
2786 begin
2787 FieldType := qryFuncArgs.FieldByName('RDB$FIELD_TYPE').AsInteger;
2788 if (FieldType = blr_cstring) or (FieldType = blr_cstring2) then
2789 Result := Format('CSTRING(%d)',[qryFuncArgs.FieldByName('RDB$FIELD_LENGTH').AsInteger]) +
2790 GetCharacterSetName(qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID').AsInteger, true)
2791 else
2792 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
2793 Result := GetFieldType(FieldType,
2794 qryFuncArgs.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger,
2795 qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger,
2796 qryFuncArgs.FieldByName('RDB$FIELD_PRECISION').AsInteger,
2797 qryFuncArgs.FieldByName('RDB$FIELD_LENGTH').AsInteger,
2798 not qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID').IsNull,
2799 true,
2800 qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID').AsInteger,
2801 qryFuncArgs.FieldByName('RDB$CHARACTER_LENGTH').AsInteger)
2802 else
2803 Result := GetFieldType(FieldType,
2804 qryFuncArgs.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger,
2805 qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger,
2806 0,
2807 qryFuncArgs.FieldByName('RDB$FIELD_LENGTH').AsInteger,
2808 not qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID').IsNull,
2809 true,
2810 qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID').AsInteger,
2811 qryFuncArgs.FieldByName('RDB$FIELD_LENGTH').AsInteger);
2812
2813 case qryFuncArgs.FieldByName('RDB$MECHANISM').AsInteger of
2814 0:
2815 if qryFuncArgs.FieldByName('RDB$ARGUMENT_POSITION').AsInteger = 0 then {Return parameter}
2816 Result := Result + ' BY VALUE';
2817
2818 2:
2819 Result := Result + ' BY DESCRIPTOR';
2820
2821 5:
2822 Result := Result + ' NULL';
2823
2824 -1:
2825 if qryFuncArgs.FieldByName('RDB$ARGUMENT_POSITION').AsInteger = 0 then {Return parameter}
2826 Result := Result + ' FREE_IT';
2827 end;
2828 end;
2829
2830 var
2831 qryFunctions, qryFuncArgs : TIBSQL;
2832 First, FirstArg: Boolean;
2833 ReturnBuffer, Line : String;
2834 Comments: TStrings;
2835 begin
2836 First := true;
2837 Comments := TStringList.Create;
2838 qryFunctions := TIBSQL.Create(FDatabase);
2839 qryFuncArgs := TIBSQL.Create(FDatabase);
2840 try
2841 if FunctionName = '' then
2842 qryFunctions.SQL.Text := FunctionSQL
2843 else
2844 begin
2845 qryFunctions.SQL.Text := FunctionNameSQL;
2846 qryFunctions.Params.ByName('FunctionName').AsString := FunctionName;
2847 end;
2848 qryFuncArgs.SQL.Text := FunctionArgsSQL;
2849 qryFunctions.ExecQuery;
2850 while not qryFunctions.Eof do
2851 begin
2852 if qryFunctions.HasField('RDB$LEGACY_FLAG') and (qryFunctions.FieldByName('RDB$LEGACY_FLAG').IsNULL or
2853 (qryFunctions.FieldByName('RDB$LEGACY_FLAG').AsInteger = 0)) then
2854 begin
2855 qryFunctions.Next;
2856 continue; {Internal stored procedure}
2857 end;
2858 if First then
2859 begin
2860 ExtractOut(Format('%s/* External Function declarations */%s',
2861 [LineEnding, LineEnding]));
2862 First := false;
2863 end; //end_if
2864 { Start new function declaration }
2865 AddComment(qryFunctions,ctExternalFunction,Comments);
2866 ExtractOut(Format('DECLARE EXTERNAL FUNCTION %s',
2867 [TrimRight(qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString)]));
2868 Line := '';
2869
2870 FirstArg := true;
2871 qryFuncArgs.Params.ByName('FUNCTION_NAME').AsString :=
2872 qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString;
2873
2874 qryFuncArgs.ExecQuery;
2875 while not qryFuncArgs.Eof do
2876 begin
2877 AddComment(qryFuncArgs,ctParameter,Comments);
2878 { Find parameter type }
2879 if qryFuncArgs.FieldByName('RDB$ARGUMENT_POSITION').AsInteger = 0 then {return argument}
2880 ReturnBuffer := GetArgumentType(qryFuncArgs)
2881 else
2882 if FirstArg then
2883 begin
2884 Line := Line + GetArgumentType(qryFuncArgs);
2885 FirstArg := false;
2886 end
2887 else
2888 Line := Line + ', ' + GetArgumentType(qryFuncArgs);
2889 qryFuncArgs.Next;
2890 end;
2891 qryFuncArgs.Close;
2892 ExtractOut(Line);
2893
2894 if qryFunctions.FieldByName('RDB$RETURN_ARGUMENT').AsInteger = 0 then
2895 ExtractOut('RETURNS ' + ReturnBuffer)
2896 else
2897 ExtractOut(Format('RETURNS PARAMETER %d',[qryFunctions.FieldByName('RDB$RETURN_ARGUMENT').AsInteger]));
2898
2899 ExtractOut(Format('ENTRY_POINT ''%s'' MODULE_NAME ''%s''',
2900 [TrimRight(qryFunctions.FieldByName('RDB$ENTRYPOINT').AsString),
2901 TrimRight(qryFunctions.FieldByName('RDB$MODULE_NAME').AsString)]));
2902
2903 {SQL Security added in Firebird 4}
2904 if (FDatabaseInfo.ODSMajorVersion >= ODS_VERSION13) and
2905 not qryFunctions.FieldByName('RDB$SQL_SECURITY').IsNull then
2906 ExtractOut(AddSQLSecurity(qryFunctions.FieldByName('RDB$SQL_SECURITY')));
2907
2908 ExtractOut(TERM + LineEnding + LineEnding);
2909
2910 qryFunctions.Next;
2911 end;
2912 ExtractOut(Comments);
2913 finally
2914 qryFunctions.Free;
2915 qryFuncArgs.Free;
2916 Comments.Free;
2917 end;
2918 end;
2919
2920 procedure TIBExtract.ListFunctions(ProcDDLType: TProcDDLType;
2921 FunctionName: String; IncludeGrants: boolean);
2922 const
2923 FunctionSQL =
2924 'SELECT * FROM RDB$FUNCTIONS WHERE RDB$SYSTEM_FLAG = 0 and RDB$LEGACY_FLAG is not NULL and RDB$LEGACY_FLAG = 0 ' +
2925 'ORDER BY RDB$FUNCTION_NAME';
2926
2927 FunctionNameSQL =
2928 'SELECT * FROM RDB$FUNCTIONS ' +
2929 'WHERE RDB$FUNCTION_NAME = :FUNCTION_NAME ' +
2930 'ORDER BY RDB$FUNCTION_NAME';
2931
2932 FunctionArgsSQL =
2933 'SELECT * FROM RDB$FUNCTION_ARGUMENTS RFA JOIN RDB$FIELDS FLD ' +
2934 'ON RFA.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME '+
2935 'WHERE RDB$FUNCTION_NAME = :FUNCTION_NAME ' +
2936 'ORDER BY RDB$ARGUMENT_POSITION';
2937
2938 var
2939 qryFunctions, qryFuncArgs : TIBSQL;
2940 First, FirstArg: Boolean;
2941 ReturnBuffer, Params : String;
2942 Comments: TStrings;
2943 begin
2944 if FDatabaseInfo.ODSMajorVersion < ODS_VERSION12 then {Nothing to do}
2945 Exit;
2946
2947 First := true;
2948 Comments := TStringList.Create;
2949 qryFunctions := TIBSQL.Create(FDatabase);
2950 qryFuncArgs := TIBSQL.Create(FDatabase);
2951 try
2952 if FunctionName = '' then
2953 qryFunctions.SQL.Text := FunctionSQL
2954 else
2955 begin
2956 qryFunctions.SQL.Text := FunctionNameSQL;
2957 qryFunctions.Params.ByName('FUNCTION_NAME').AsString := FunctionName;
2958 end;
2959 qryFuncArgs.SQL.Text := FunctionArgsSQL;
2960 qryFunctions.ExecQuery;
2961 while not qryFunctions.Eof do
2962 begin
2963 if First then
2964 begin
2965 ExtractOut('COMMIT WORK;');
2966 ExtractOut('SET AUTODDL OFF;');
2967 ExtractOut(Format('SET TERM %s%s', [ProcTerm, Term]));
2968 ExtractOut('');
2969 if ProcDDLType in [pdCreateStub,pdCreateProc] then
2970 ExtractOut('/* Stored Function declarations */')
2971 else
2972 ExtractOut('/* Stored Function Body */');
2973 ExtractOut('');
2974 First := false;
2975 end;
2976
2977 AddComment(qryFunctions,ctFunction,Comments);
2978 Params := '';
2979
2980 FirstArg := true;
2981 qryFuncArgs.Params.ByName('FUNCTION_NAME').AsString :=
2982 trim(qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString);
2983
2984 qryFuncArgs.ExecQuery;
2985 while not qryFuncArgs.Eof do
2986 begin
2987 AddComment(qryFuncArgs,ctParameter,Comments);
2988 if qryFuncArgs.FieldByName('RDB$ARGUMENT_POSITION').AsInteger = 0 then {return argument}
2989 ReturnBuffer := ' RETURNS ' + GetFieldType(qryFuncArgs.FieldByName('RDB$FIELD_TYPE1').AsInteger,
2990 qryFuncArgs.FieldByName('RDB$FIELD_SUB_TYPE1').AsInteger,
2991 qryFuncArgs.FieldByName('RDB$FIELD_SCALE1').AsInteger,
2992 qryFuncArgs.FieldByName('RDB$FIELD_PRECISION1').AsInteger,
2993 qryFuncArgs.FieldByName('RDB$FIELD_LENGTH1').AsInteger,
2994 not qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID1').IsNull,
2995 true,
2996 qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID1').AsInteger,
2997 qryFuncArgs.FieldByName('RDB$CHARACTER_LENGTH1').AsInteger)
2998 else
2999 begin
3000 if not FirstArg then
3001 begin
3002 Params := Params + ', ';
3003 FirstArg := false;
3004 end;
3005 Params := Params + TrimRight(qryFuncArgs.FieldByName('RDB$ARGUMENT_NAME').AsString) + ' ' +
3006 GetFieldType(qryFuncArgs.FieldByName('RDB$FIELD_TYPE1').AsInteger,
3007 qryFuncArgs.FieldByName('RDB$FIELD_SUB_TYPE1').AsInteger,
3008 qryFuncArgs.FieldByName('RDB$FIELD_SCALE1').AsInteger,
3009 qryFuncArgs.FieldByName('RDB$FIELD_PRECISION1').AsInteger,
3010 qryFuncArgs.FieldByName('RDB$FIELD_LENGTH1').AsInteger,
3011 not qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID1').IsNull,
3012 true,
3013 qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID1').AsInteger,
3014 qryFuncArgs.FieldByName('RDB$CHARACTER_LENGTH1').AsInteger);
3015 end;
3016 qryFuncArgs.Next;
3017 end; // qryFuncArgs Iteration
3018 qryFuncArgs.Close;
3019
3020 case ProcDDLType of
3021 pdCreateStub:
3022 begin
3023 if Params <> '' then
3024 ExtractOut(Format('CREATE FUNCTION %s (%s)',
3025 [TrimRight(qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString), Params]))
3026 else
3027 ExtractOut(Format('CREATE FUNCTION %s',[TrimRight(qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString)]));
3028 ExtractOut(ReturnBuffer);
3029 ExtractOut(' AS BEGIN END');
3030
3031 {SQL Security added in Firebird 4}
3032 if (FDatabaseInfo.ODSMajorVersion >= ODS_VERSION13) and
3033 not qryFunctions.FieldByName('RDB$SQL_SECURITY').IsNull then
3034 ExtractOut(AddSQLSecurity(qryFunctions.FieldByName('RDB$SQL_SECURITY')));
3035 end;
3036
3037 pdCreateProc:
3038 begin
3039 if Params <> '' then
3040 ExtractOut(Format('CREATE FUNCTION %s (%s)',
3041 [TrimRight(qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString), Params]))
3042 else
3043 ExtractOut(Format('CREATE FUNCTION %s',[TrimRight(qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString)]));
3044 ExtractOut(ReturnBuffer);
3045 if not qryFunctions.FieldByName('RDB$FUNCTION_SOURCE').IsNull then
3046 ExtractOut('AS' + LineEnding + qryFunctions.FieldByName('RDB$FUNCTION_SOURCE').AsString)
3047 else
3048 ExtractOut('AS BEGIN END');
3049
3050 {SQL Security added in Firebird 4}
3051 if (FDatabaseInfo.ODSMajorVersion >= ODS_VERSION13) and
3052 not qryFunctions.FieldByName('RDB$SQL_SECURITY').IsNull then
3053 ExtractOut(AddSQLSecurity(qryFunctions.FieldByName('RDB$SQL_SECURITY')));
3054 end;
3055
3056 pdAlterProc:
3057 begin
3058 if Params <> '' then
3059 ExtractOut(Format('ALTER FUNCTION %s (%s)',
3060 [TrimRight(qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString),Params]))
3061 else
3062 ExtractOut(Format('ALTER FUNCTION %s',
3063 [TrimRight(qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString)]));
3064 ExtractOut(ReturnBuffer);
3065 if not qryFunctions.FieldByName('RDB$FUNCTION_SOURCE').IsNull then
3066 ExtractOut('AS' + LineEnding + qryFunctions.FieldByName('RDB$FUNCTION_SOURCE').AsString)
3067 else
3068 ExtractOut('AS BEGIN END');
3069 end;
3070 end;
3071 ExtractOut(ProcTerm + LineEnding);
3072 if IncludeGrants then
3073 ShowGrantsTo(qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsString,obj_Function,ProcTerm);
3074
3075 qryFunctions.Next;
3076 end; // qryFunctions Iteration
3077
3078 if not First then
3079 begin
3080 ExtractOut(Format('SET TERM %s%s', [Term, ProcTerm]));
3081 ExtractOut('COMMIT WORK;');
3082 ExtractOut('SET AUTODDL ON;');
3083 end;
3084 ExtractOut(Comments);
3085 finally
3086 qryFunctions.Free;
3087 qryFuncArgs.Free;
3088 Comments.Free;
3089 end;
3090 end;
3091
3092 { ListGenerators
3093 Functional description
3094 Re create all non-system generators }
3095
3096 procedure TIBExtract.ListGenerators(GeneratorName: String;
3097 ExtractTypes: TExtractTypes);
3098 const
3099 GeneratorSQL =
3100 'SELECT RDB$GENERATOR_NAME ' +
3101 'FROM RDB$GENERATORS ' +
3102 'WHERE ' +
3103 ' (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG <> 1) ' +
3104 'ORDER BY RDB$GENERATOR_NAME';
3105
3106 GeneratorNameSQL =
3107 'SELECT RDB$GENERATOR_NAME ' +
3108 'FROM RDB$GENERATORS ' +
3109 'WHERE RDB$GENERATOR_NAME = :GeneratorName AND ' +
3110 ' (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG <> 1) ' +
3111 'ORDER BY RDB$GENERATOR_NAME';
3112
3113 GeneratorValueSQL =
3114 'SELECT GEN_ID(%s,0) as GENERATORVALUE From RDB$Database';
3115
3116 var
3117 qryGenerator : TIBSQL;
3118 qryValue: TIBSQL;
3119 GenName : String;
3120 NextSeq: int64;
3121 begin
3122 qryGenerator := TIBSQL.Create(FDatabase);
3123 qryValue := TIBSQL.Create(FDatabase);
3124 try
3125 if GeneratorName = '' then
3126 qryGenerator.SQL.Text := GeneratorSQL
3127 else
3128 begin
3129 qryGenerator.SQL.Text := GeneratorNameSQL;
3130 qryGenerator.Params.ByName('GeneratorName').AsString := GeneratorName;
3131 end;
3132 qryGenerator.ExecQuery;
3133 ExtractOut('');
3134 while not qryGenerator.Eof do
3135 begin
3136 GenName := qryGenerator.FieldByName('RDB$GENERATOR_NAME').AsString;
3137 if ((Pos('RDB$',GenName) = 1) and
3138 (GenName[5] in ['0'..'9'])) or
3139 ((Pos('SQL$',GenName) = 1) and
3140 (GenName[5] in ['0'..'9'])) then
3141 begin
3142 qryGenerator.Next;
3143 continue;
3144 end;
3145 ExtractOut(Format('CREATE SEQUENCE %s%s',
3146 [QuoteIdentifier( GenName),
3147 Term]));
3148 if etData in ExtractTypes then
3149 begin
3150 qryValue.SQL.Text := Format(GeneratorValueSQL,[GenName]);
3151 qryValue.ExecQuery;
3152 try
3153 if not qryValue.EOF then
3154 begin
3155 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION13 then
3156 NextSeq := qryValue.FieldByName('GENERATORVALUE').AsInt64 + 1
3157 else
3158 NextSeq := qryValue.FieldByName('GENERATORVALUE').AsInt64;
3159 ExtractOut(Format('ALTER SEQUENCE %s RESTART WITH %d;',
3160 [QuoteIdentifier( GenName),NextSeq]));
3161 end;
3162 finally
3163 qryValue.Close;
3164 end;
3165 end;
3166 AddComment(qryGenerator,ctSequence);
3167 qryGenerator.Next;
3168 end;
3169 finally
3170 qryGenerator.Free;
3171 qryValue.Free;
3172 end;
3173 end;
3174
3175 { ListIndex
3176 Functional description
3177 Define all non-constraint indices
3178 Use a static SQL query to get the info and print it.
3179
3180 Uses get_index_segment to provide a key list for each index }
3181
3182 procedure TIBExtract.ListIndex(ObjectName : String; ExtractType : TExtractType);
3183 const
3184 IndexSQL =
3185 'SELECT IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, IDX.RDB$UNIQUE_FLAG, ' +
3186 ' IDX.RDB$INDEX_TYPE ' +
3187 'FROM RDB$INDICES IDX JOIN RDB$RELATIONS RELC ON ' +
3188 ' IDX.RDB$RELATION_NAME = RELC.RDB$RELATION_NAME ' +
3189 'WHERE (RELC.RDB$SYSTEM_FLAG <> 1 OR RELC.RDB$SYSTEM_FLAG IS NULL) 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 IndexNameSQL =
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 ' RELC.RDB$RELATION_NAME = :RelationName 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 IndexByNameSQL =
3206 'SELECT IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, IDX.RDB$UNIQUE_FLAG, ' +
3207 ' IDX.RDB$INDEX_TYPE ' +
3208 'FROM RDB$INDICES IDX JOIN RDB$RELATIONS RELC ON ' +
3209 ' IDX.RDB$RELATION_NAME = RELC.RDB$RELATION_NAME ' +
3210 'WHERE (RELC.RDB$SYSTEM_FLAG <> 1 OR RELC.RDB$SYSTEM_FLAG IS NULL) AND ' +
3211 ' IDX.RDB$INDEX_NAME = :IndexName AND ' +
3212 ' NOT EXISTS (SELECT * FROM RDB$RELATION_CONSTRAINTS RC ' +
3213 ' WHERE RC.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME) ' +
3214 'ORDER BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME';
3215
3216 var
3217 qryIndex : TIBSQL;
3218 First : Boolean;
3219 Unique, IdxType, Line : String;
3220 begin
3221 First := true;
3222 qryIndex := TIBSQL.Create(FDatabase);
3223 try
3224 if ObjectName = '' then
3225 qryIndex.SQL.Text := IndexSQL
3226 else
3227 begin
3228 if ExtractType = etTable then
3229 begin
3230 qryIndex.SQL.Text := IndexNameSQL;
3231 qryIndex.Params.ByName('RelationName').AsString := ObjectName;
3232 end
3233 else
3234 begin
3235 qryIndex.SQL.Text := IndexByNameSQL;
3236 qryIndex.Params.ByName('IndexName').AsString := ObjectName;
3237 end;
3238 end;
3239 qryIndex.ExecQuery;
3240 while not qryIndex.Eof do
3241 begin
3242 if First then
3243 begin
3244 if ObjectName = '' then
3245 ExtractOut(LineEnding + '/* Index definitions for all user tables */' + LineEnding)
3246 else
3247 ExtractOut(LineEnding + '/* Index definitions for ' + ObjectName + ' */' + LineEnding);
3248 First := false;
3249 end; //end_if
3250
3251 if qryIndex.FieldByName('RDB$UNIQUE_FLAG').AsInteger = 1 then
3252 Unique := ' UNIQUE'
3253 else
3254 Unique := '';
3255
3256 if qryIndex.FieldByName('RDB$INDEX_TYPE').AsInteger = 1 then
3257 IdxType := ' DESCENDING'
3258 else
3259 IdxType := '';
3260
3261 Line := Format('CREATE%s%s INDEX %s ON %s(', [Unique, IdxType,
3262 QuoteIdentifier(
3263 qryIndex.FieldByName('RDB$INDEX_NAME').AsString),
3264 QuoteIdentifier(
3265 qryIndex.FieldByName('RDB$RELATION_NAME').AsString)]);
3266
3267 Line := Line + GetIndexSegments(qryIndex.FieldByName('RDB$INDEX_NAME').AsString) +
3268 ')' + Term;
3269
3270 ExtractOut(Line);
3271 AddComment(qryIndex,ctIndex);
3272 qryIndex.Next;
3273 end;
3274 finally
3275 qryIndex.Free;
3276 end;
3277 end;
3278
3279 { ListViews
3280 Functional description
3281 Show text of views.
3282 Use a SQL query to get the info and print it.
3283 Note: This should also contain check option }
3284
3285 procedure TIBExtract.ListViews(ViewName : String);
3286 const
3287 ViewSQL =
3288 'with recursive Views as ( ' +
3289 ' Select RDB$RELATION_NAME, 1 as ViewLevel from RDB$RELATIONS ' +
3290 ' Where RDB$RELATION_TYPE = 1 and RDB$SYSTEM_FLAG = 0 '+
3291 ' UNION ALL ' +
3292 ' Select D.RDB$DEPENDED_ON_NAME, ViewLevel + 1 From RDB$DEPENDENCIES D ' +
3293 ' JOIN Views on Views.RDB$RELATION_NAME = D.RDB$DEPENDENT_NAME ' +
3294 ' and Views.RDB$RELATION_NAME <> D.RDB$DEPENDED_ON_NAME ' +
3295 ' JOIN RDB$RELATIONS R On R.RDB$RELATION_NAME = D.RDB$DEPENDED_ON_NAME ' +
3296 ')' +
3297 'SELECT R.RDB$RELATION_NAME, R.RDB$OWNER_NAME, R.RDB$VIEW_SOURCE FROM RDB$RELATIONS R ' +
3298 'JOIN ( ' +
3299 'Select RDB$RELATION_NAME, max(ViewLevel) as ViewLevel From Views ' +
3300 'Group By RDB$RELATION_NAME) A On A.RDB$RELATION_NAME = R.RDB$RELATION_NAME ' +
3301 'Where R.RDB$RELATION_TYPE = 1 and R.RDB$SYSTEM_FLAG = 0 '+
3302 'Order by A.ViewLevel desc, R.RDB$RELATION_NAME asc';
3303
3304 {
3305 'SELECT RDB$RELATION_NAME, RDB$OWNER_NAME, RDB$VIEW_SOURCE ' +
3306 'FROM RDB$RELATIONS ' +
3307 'WHERE ' +
3308 ' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' +
3309 ' NOT RDB$VIEW_BLR IS NULL AND ' +
3310 ' RDB$FLAGS = 1 ' +
3311 'ORDER BY RDB$RELATION_ID'; }
3312
3313 ViewNameSQL =
3314 'SELECT RDB$RELATION_NAME, RDB$OWNER_NAME, RDB$VIEW_SOURCE ' +
3315 'FROM RDB$RELATIONS ' +
3316 'WHERE ' +
3317 ' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' +
3318 ' NOT RDB$VIEW_BLR IS NULL AND ' +
3319 ' RDB$FLAGS = 1 AND ' +
3320 ' RDB$RELATION_NAME = :ViewName ' +
3321 'ORDER BY RDB$RELATION_ID';
3322
3323 ColumnSQL =
3324 'SELECT RDB$FIELD_NAME FROM RDB$RELATION_FIELDS ' +
3325 'WHERE ' +
3326 ' RDB$RELATION_NAME = :RELATION_NAME ' +
3327 'ORDER BY RDB$FIELD_POSITION';
3328
3329 var
3330 qryView, qryColumns : TIBSQL;
3331 SList : TStrings;
3332 begin
3333 qryView := TIBSQL.Create(FDatabase);
3334 qryColumns := TIBSQL.Create(FDatabase);
3335 SList := TStringList.Create;
3336 try
3337 if ViewName = '' then
3338 qryView.SQL.Text := ViewSQL
3339 else
3340 begin
3341 qryView.SQL.Text := ViewNameSQL;
3342 qryView.Params.ByName('ViewName').AsString := ViewName;
3343 end;
3344 qryColumns.SQL.Text := ColumnSQL;
3345 qryView.ExecQuery;
3346 while not qryView.Eof do
3347 begin
3348 SList.Add(Format('%s/* View: %s, Owner: %s */%s',
3349 [LineEnding, TrimRight(qryView.FieldByName('RDB$RELATION_NAME').AsString),
3350 TrimRight(qryView.FieldByName('RDB$OWNER_NAME').AsString), LineEnding]));
3351
3352 SList.Add(Format('CREATE VIEW %s (', [QuoteIdentifier(
3353 qryView.FieldByName('RDB$RELATION_NAME').AsString)]));
3354
3355 qryColumns.Params.ByName('RELATION_NAME').AsString :=
3356 qryView.FieldByName('RDB$RELATION_NAME').AsString;
3357 qryColumns.ExecQuery;
3358 while not qryColumns.Eof do
3359 begin
3360 SList.Add(' ' + QuoteIdentifier(
3361 qryColumns.FieldByName('RDB$FIELD_NAME').AsString));
3362 qryColumns.Next;
3363 if not qryColumns.Eof then
3364 SList.Strings[SList.Count - 1] := SList.Strings[SList.Count - 1] + ',';
3365 end;
3366 qryColumns.Close;
3367 SList.Text := SList.Text + ') AS';
3368 if not qryView.FieldByName('RDB$VIEW_SOURCE').IsNull then
3369 SList.Text := SList.Text + qryView.FieldByName('RDB$VIEW_SOURCE').AsString;
3370 SList.Text := SList.Text + Format('%s%s', [Term, LineEnding]);
3371 ExtractOut(SList);
3372 SList.Clear;
3373 qryView.Next;
3374 end;
3375 finally
3376 qryView.Free;
3377 qryColumns.Free;
3378 SList.Free;
3379 end;
3380 end;
3381
3382 { PrintSet
3383 Functional description
3384 print (using ISQL_printf) the word "SET"
3385 if the first line of the ALTER DATABASE
3386 settings options. Also, add trailing
3387 comma for end of prior line if needed.
3388
3389 uses Print_buffer, a global }
3390
3391 function TIBExtract.PrintSet(var Used: Boolean) : String;
3392 begin
3393 if not Used then
3394 begin
3395 Result := ' SET ';
3396 Used := true;
3397 end
3398 else
3399 Result := Format(', %s ', [LineEnding]);
3400 end;
3401
3402 {
3403 PrintValidation
3404 Functional description
3405 This does some minor syntax adjustmet for extracting
3406 validation blobs and computed fields.
3407 if it does not start with the word CHECK
3408 if this is a computed field blob,look for () or insert them.
3409 if flag = false, this is a validation clause,
3410 if flag = true, this is a computed field }
3411
3412 function TIBExtract.PrintValidation(ToValidate: String;
3413 flag: Boolean): String;
3414 var
3415 IsSQL : Boolean;
3416 begin
3417 IsSql := false;
3418
3419 Result := '';
3420 ToValidate := Trim(ToValidate);
3421
3422 if flag then
3423 begin
3424 if ToValidate[1] = '(' then
3425 IsSQL := true;
3426 end
3427 else
3428 if (Pos(ToValidate, 'check') = 1) or (Pos(ToValidate, 'CHECK') = 1) then
3429 IsSQL := TRUE;
3430
3431 if not IsSQL then
3432 begin
3433 if Flag then
3434 Result := Result + '/* ' + ToValidate + ' */'
3435 else
3436 Result := Result + '(' + ToValidate + ')';
3437 end
3438 else
3439 Result := ToValidate;
3440 end;
3441
3442 procedure TIBExtract.SetDatabase(const Value: TIBDatabase);
3443 begin
3444 if (csLoading in ComponentState) or (FDatabase <> Value) then
3445 begin
3446 FDatabase := Value;
3447 if (not Assigned(FTransaction)) and (FDatabase <> nil) then
3448 Transaction := FDatabase.DefaultTransaction;
3449 FDatabaseInfo.Database := FDatabase;
3450 end;
3451 end;
3452
3453 procedure TIBExtract.SetTransaction(const Value: TIBTransaction);
3454 begin
3455 if FTransaction <> Value then
3456 begin
3457 FTransaction := Value;
3458 if (not Assigned(FDatabase)) and (FTransaction <> nil) then
3459 Database := FTransaction.DefaultDatabase;
3460 end;
3461 end;
3462
3463 procedure TIBExtract.ExtractObject(ObjectType : TExtractObjectTypes;
3464 ObjectName : String = ''; ExtractTypes : TExtractTypes = []);
3465 var
3466 DidActivate : Boolean;
3467 begin
3468 DidActivate := false;
3469 if not FTransaction.Active then
3470 begin
3471 FTransaction.StartTransaction;
3472 DidActivate := true;
3473 end;
3474 FMetaData.Clear;
3475 if not CaseSensitiveObjectNames then
3476 ObjectName := ExtractIdentifier(FDatabaseInfo.DBSQLDialect,ObjectName);
3477 case ObjectType of
3478 eoDatabase : ExtractDDL(true, '', ExtractTypes);
3479 eoDomain :
3480 if etTable in ExtractTypes then
3481 ListDomains(dtCreateDomain,ObjectName, etTable)
3482 else
3483 ListDomains(dtCreateDomain,ObjectName);
3484 eoTable :
3485 begin
3486 if ObjectName <> '' then
3487 begin
3488 if etDomain in ExtractTypes then
3489 ListDomains(dtCreateDomain,ObjectName, etTable);
3490 ExtractListTable(ObjectName, '', false);
3491 if etIndex in ExtractTypes then
3492 ListIndex(ObjectName, etTable);
3493 if etForeign in ExtractTypes then
3494 ListForeign(ObjectName, etTable);
3495 if etCheck in ExtractTypes then
3496 ListCheck(ObjectName, etTable);
3497 if etTrigger in ExtractTypes then
3498 begin
3499 if etGrant in ExtractTypes then
3500 ListTriggers(ObjectName, [etTable,etGrant])
3501 else
3502 ListTriggers(ObjectName, [etTable]);
3503 end;
3504 if etGrant in ExtractTypes then
3505 ShowGrants(ObjectName, Term);
3506 if etData in ExtractTypes then
3507 ListData(ObjectName);
3508 end
3509 else
3510 ListAllTables(true);
3511 end;
3512 eoView :
3513 begin
3514 ListViews(ObjectName);
3515 if ObjectName <> '' then
3516 begin
3517 if etTrigger in ExtractTypes then
3518 begin
3519 if etGrant in ExtractTypes then
3520 ListTriggers(ObjectName, [etTable,etGrant])
3521 else
3522 ListTriggers(ObjectName, [etTable]);
3523 end;
3524 if etGrant in ExtractTypes then
3525 ShowGrants(ObjectName, Term);
3526 end;
3527 end;
3528 eoProcedure :
3529 begin
3530 ListProcs(pdCreateProc,ObjectName,etGrant in ExtractTypes);
3531 ListFunctions(pdCreateProc,ObjectName,etGrant in ExtractTypes);
3532 if (ObjectName <> '' ) and (etGrant in ExtractTypes) then
3533 ShowGrants(ObjectName, Term);
3534 end;
3535 eoPackage:
3536 begin
3537 if DatabaseInfo.ODSMajorVersion >= ODS_VERSION12 then
3538 begin
3539 ListPackages(paBoth,ObjectName, etGrant in ExtractTypes);
3540 if (ObjectName <> '' ) and (etGrant in ExtractTypes) then
3541 ShowGrants(ObjectName, Term);
3542 end
3543 else
3544 IBError(ibxeODSVersionRequired,['12.0']);
3545 end;
3546 eoFunction : ListExternalFunctions(ObjectName);
3547 eoGenerator : ListGenerators(ObjectName,ExtractTypes);
3548 eoException : ListException(ObjectName);
3549 eoBLOBFilter : ListFilters(ObjectName);
3550 eoRole : ListRoles(ObjectName,etGrant in ExtractTypes);
3551 eoTrigger :
3552 if etTable in ExtractTypes then
3553 ListTriggers(ObjectName, ExtractTypes * [etTable,etGrant])
3554 else
3555 if ExtractTypes * [etDatabaseTriggers,etDDLTriggers] = [] then
3556 ListTriggers(ObjectName,[etTrigger] + (ExtractTypes * [etGrant]))
3557 else
3558 ListTriggers(ObjectName,ExtractTypes * [etDatabaseTriggers,etDDLTriggers, etGrant]);
3559 eoForeign :
3560 if etTable in ExtractTypes then
3561 ListForeign(ObjectName, etTable)
3562 else
3563 ListForeign(ObjectName);
3564 eoIndexes :
3565 if etTable in ExtractTypes then
3566 ListIndex(ObjectName, etTable)
3567 else
3568 ListIndex(ObjectName);
3569 eoChecks :
3570 if etTable in ExtractTypes then
3571 ListCheck(ObjectName, etTable)
3572 else
3573 ListCheck(ObjectName);
3574 eoComments:
3575 ListComments;
3576 eoData : ListData(ObjectName);
3577 end;
3578 if DidActivate then
3579 FTransaction.Commit;
3580 end;
3581
3582 procedure TIBExtract.ListObjectNames(ObjectType: integer; Names: TStrings);
3583 var qryObjects: TIBSQL;
3584 i, index: integer;
3585 sql: string;
3586 begin
3587 index := -1;
3588 Names.Clear;
3589 for i := Low(DDLObjects) to High(DDLObjects) do
3590 begin
3591 if DDLObjects[i].ObjType = ObjectType then
3592 begin
3593 index := i;
3594 break;
3595 end;
3596 end;
3597 if index = -1 then Exit;
3598
3599 qryObjects := TIBSQL.Create(FDatabase);
3600 try
3601 with DDLObjects[index] do
3602 begin
3603 sql := 'Select ' + NameField + ' From ' + SystemTableName;
3604 if not ShowSystem then
3605 sql += ' Where (RDB$SYSTEM_FLAG is null or RDB$SYSTEM_FLAG = 0)';
3606 if Condition <> '' then
3607 begin
3608 if not ShowSystem then
3609 sql += ' AND ' + Condition
3610 else
3611 sql += ' Where ' + Condition;
3612 end;
3613 sql += ' Order by 1';
3614 end;
3615
3616 qryObjects.SQL.Text := sql;
3617 qryObjects.ExecQuery;
3618 while not qryObjects.Eof do
3619 begin
3620 Names.Add(qryObjects.Fields[0].AsString);
3621 qryObjects.Next;
3622 end;
3623 finally
3624 qryObjects.Free;
3625 end;
3626 end;
3627
3628 function TIBExtract.GetCharacterSetName(CharSetID: integer; ForceCharSet: boolean): string;
3629 {If ForceCharSet is true then Character Set always added. Otherwise returns empty if charset is
3630 database default}
3631 const
3632 GetCharacterSetSQL =
3633 'SELECT CST.RDB$CHARACTER_SET_NAME ' +
3634 'FROM RDB$CHARACTER_SETS CST ' +
3635 'WHERE CST.RDB$CHARACTER_SET_ID = :CHARSETID ' +
3636 'ORDER BY CST.RDB$CHARACTER_SET_NAME';
3637
3638 var CharSetSQL : TIBSQL;
3639 CharSetName: string;
3640 begin
3641 Result := '';
3642 CharSetSQL := TIBSQL.Create(FDatabase);
3643 try
3644 CharSetSQL.SQL.Add(GetCharacterSetSQL);
3645 CharSetSQL.Params.ByName('CHARSETID').AsInteger := CharSetID;
3646 CharSetSQL.ExecQuery;
3647 if (CharSetSQL.RecordCount > 0) then
3648 begin
3649 CharSetName := Trim(CharSetSQL.FieldByName('RDB$CHARACTER_SET_NAME').AsString);
3650 if ForceCharSet or (FDefaultCharSetName <> CharSetName) then
3651 Result := ' CHARACTER SET ' + CharSetName;
3652 end;
3653 finally
3654 CharSetSQL.Free;
3655 end;
3656 end;
3657
3658
3659 function TIBExtract.GetFieldType(FieldType, FieldSubType, FieldScale,
3660 FieldPrecision, FieldLength: integer; HasCharacterSet: boolean;
3661 ForceCharSet: boolean; FieldCharacterSetID: integer;
3662 FieldCharacterLength: integer; FieldSegmentLen: integer; IsArray: boolean;
3663 FieldSourceName: string): String;
3664 var i: integer;
3665 TypeName: string;
3666 DidActivate : Boolean;
3667 begin
3668 Result := '';
3669 if not FTransaction.Active then
3670 begin
3671 FTransaction.StartTransaction;
3672 DidActivate := true;
3673 end
3674 else
3675 DidActivate := false;
3676
3677 { Look through types array }
3678 for i := Low(Columntypes) to High(ColumnTypes) do
3679 begin
3680 if FieldType = ColumnTypes[i].SQLType then {Process this and forget the rest}
3681 begin
3682 TypeName := ColumnTypes[i].TypeName;
3683
3684 case FieldType of
3685 blr_text,
3686 blr_varying: {CHAR and VARCHAR}
3687 begin
3688 if FieldCharacterLength = 0 then
3689 Result := TypeName + Format('(%d)', [FieldLength])
3690 else
3691 Result := TypeName + Format('(%d)', [FieldCharacterLength]);
3692 if HasCharacterSet then
3693 Result := Result + GetCharacterSetName(FieldCharacterSetID,ForceCharSet);
3694 end;
3695
3696 blr_blob:
3697 begin
3698 if (FieldSubType > 0) and (FieldSubType <= MAXSUBTYPES) then
3699 Result := TypeName + ' SUB_TYPE ' + SubTypes[FieldSubType]
3700 else
3701 Result := TypeName + ' SUB_TYPE ' + IntToStr(FieldSubType);
3702
3703 if FieldSegmentLen > 0 then
3704 Result := Result + Format(' SEGMENT SIZE %d',[FieldSegmentLen]);
3705 if HasCharacterSet then
3706 Result := Result + GetCharacterSetName(FieldCharacterSetID,ForceCharSet);
3707 end;
3708
3709 blr_dec64: {DecFloat(16) }
3710 begin
3711 if FieldPrecision = 0 then
3712 Result := TypeName + '(16)'
3713 else
3714 Result := TypeName + Format('(%d)',[FieldPrecision]);
3715 end;
3716
3717 blr_dec128: { DecFloat(34)}
3718 begin
3719 if FieldPrecision = 0 then
3720 Result := TypeName + '(34)'
3721 else
3722 Result := TypeName + Format('(%d)',[FieldPrecision]);
3723 end;
3724
3725 blr_short,
3726 blr_long,
3727 blr_double,
3728 blr_int64,
3729 blr_int128: {numeric types}
3730 begin
3731 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
3732 begin
3733 { We are ODS >= 10 and could be any Dialect }
3734 if FieldPrecision > 0 then
3735 begin
3736 { We are Dialect >=3 since FIELD_PRECISION is non-NULL }
3737 if (FieldSubType > 0) and (FieldSubType <= MAX_INTSUBTYPES) then
3738 begin
3739 Result := Format('%s(%d,%d)',
3740 [IntegralSubtypes[FieldSubType],
3741 FieldPrecision,
3742 -FieldScale]);
3743 break;
3744 end;
3745 end;
3746 end;
3747
3748 { Take a stab at numerics and decimals }
3749 if (FieldType = blr_short) and (FieldScale < 0) then
3750 Result := Format('NUMERIC(4,%d)', [-FieldScale])
3751 else
3752 if (FieldType = blr_long) and (FieldScale < 0) then
3753 Result := Format('NUMERIC(9,%d)', [-FieldScale])
3754 else
3755 if (FieldType = blr_double) and (FieldScale < 0) then
3756 Result := Format('NUMERIC(15,%d)', [-FieldScale])
3757 else
3758 if (FieldType = blr_int64) and (FieldScale < 0) then
3759 Result := Format('NUMERIC(18,%d)', [-FieldScale])
3760 else
3761 if (FieldType = blr_int128) and (FieldScale < 0) then
3762 Result := Format('NUMERIC(38,%d)', [-FieldScale])
3763 else
3764 Result := TypeName;
3765 end;
3766
3767 else
3768 Result := TypeName; {e.g. Timestamp}
3769 end;
3770
3771 { Catch arrays after detrermining the type declaration }
3772 if IsArray then
3773 Result := Result + GetArrayField(FieldSourceName);
3774 Break;
3775 end;
3776 end;
3777 if DidActivate then
3778 FTransaction.Commit;
3779 end;
3780
3781 { S H O W _ g r a n t s
3782 Functional description
3783 Show grants for given object name
3784 This function is also called by extract for privileges.
3785 It must extract granted privileges on tables/views to users,
3786 - these may be compound, so put them on the same line.
3787 Grant execute privilege on procedures to users
3788 Grant various privileges to procedures.
3789 All privileges may have the with_grant option set. }
3790
3791 procedure TIBExtract.ShowGrants(MetaObject: String; Terminator: String;
3792 NoUserGrants: boolean);
3793 const
3794 GrantsBaseSelect =
3795 'Select Trim(RDB$USER) as RDB$USER,List("Privileges") as Privileges, '+
3796 'coalesce(RDB$GRANT_OPTION,0) as RDB$GRANT_OPTION,METAOBJECTNAME, '+
3797 'RDB$USER_TYPE, RDB$OBJECT_TYPE, '+
3798 'case T2.RDB$TYPE_NAME '+
3799 ' When ''RELATION'' then ''TABLE'' '+
3800 ' When ''FIELD'' then ''DOMAIN'' '+
3801 'Else T2.RDB$TYPE_NAME End as OBJECT_TYPE_NAME, '+
3802 'T1.RDB$TYPE_NAME as USER_TYPE_NAME, '+
3803 'case '+
3804 'When coalesce(RDB$GRANT_OPTION,0) <> 0 and RDB$USER_TYPE = 13 then '' WITH ADMIN OPTION'' '+
3805 'When coalesce(RDB$GRANT_OPTION,0) <> 0 and RDB$USER_TYPE <> 13 then '' WITH GRANT OPTION'' '+
3806 'ELSE '''' End as GRANTOPTION, '+
3807 'case When RDB$OWNER_NAME = RDB$GRANTOR then NULL '+
3808 'else Trim(RDB$GRANTOR) End as GRANTEDBY '+
3809 'From ( '+
3810 'Select PR.RDB$USER,PR.RDB$RELATION_NAME as METAOBJECTNAME, LIST(DISTINCT Trim(Case PR.RDB$PRIVILEGE '+
3811 'When ''X'' then ''EXECUTE'' '+
3812 'When ''S'' then ''SELECT'' '+
3813 'When ''U'' then ''UPDATE'' '+
3814 'When ''D'' then ''DELETE'' '+
3815 'When ''R'' then ''REFERENCES'' '+
3816 'When ''G'' then ''USAGE'' '+
3817 'When ''I'' then ''INSERT'' '+
3818 'end )) as "Privileges", '+
3819 'PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE,OW.RDB$OWNER_NAME,PR.RDB$GRANTOR '+
3820 'FROM RDB$USER_PRIVILEGES PR '+
3821 'JOIN ObjectOwners OW On OW.METAOBJECTNAME = PR.RDB$RELATION_NAME and OW.ObjectType = PR.RDB$OBJECT_TYPE '+
3822 'Where PR.RDB$PRIVILEGE <> ''M'' and (PR.RDB$PRIVILEGE <> ''U'' or PR.RDB$FIELD_NAME is null) '+
3823 '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 '+
3824 'UNION '+
3825 'Select PR.RDB$USER,PR.RDB$RELATION_NAME, ''Update('' || List(Trim(PR.RDB$FIELD_NAME)) || '')'', '+
3826 'PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE, OW.RDB$OWNER_NAME,PR.RDB$GRANTOR '+
3827 'FROM RDB$USER_PRIVILEGES PR '+
3828 'JOIN ObjectOwners OW On OW.METAOBJECTNAME = PR.RDB$RELATION_NAME and OW.ObjectType = PR.RDB$OBJECT_TYPE '+
3829 'Where PR.RDB$PRIVILEGE = ''U'' and PR.RDB$FIELD_NAME is not null '+
3830 '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 '+
3831 'JOIN RDB$TYPES T1 On T1.RDB$TYPE = RDB$USER_TYPE and T1.RDB$FIELD_NAME = ''RDB$OBJECT_TYPE'' '+
3832 'JOIN RDB$TYPES T2 On T2.RDB$TYPE = RDB$OBJECT_TYPE and T2.RDB$FIELD_NAME = ''RDB$OBJECT_TYPE'' '+
3833 'Where METAOBJECTNAME = :METAOBJECTNAME and RDB$USER <> RDB$OWNER_NAME '+
3834 '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 '+
3835 'ORDER BY RDB$USER, RDB$OBJECT_TYPE';
3836
3837 GrantsSQL12 =
3838 'with ObjectOwners As ( '+
3839 ' Select RDB$RELATION_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 0 as ObjectType '+
3840 ' From RDB$RELATIONS '+
3841 ' UNION '+
3842 ' Select RDB$PROCEDURE_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 5 as ObjectType '+
3843 ' From RDB$PROCEDURES '+
3844 ' UNION '+
3845 ' Select RDB$FUNCTION_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 100 as ObjectType '+
3846 ' From RDB$FUNCTIONS '+
3847 ' UNION '+
3848 ' Select RDB$EXCEPTION_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 7 as ObjectType '+
3849 ' From RDB$EXCEPTIONS '+
3850 ' UNION '+
3851 ' Select RDB$FIELD_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 9 as ObjectType '+
3852 ' From RDB$FIELDS Where RDB$FIELD_NAME not Similar to ''RDB$%|SEC$%|MON$%|SQL$%'' '+
3853 ' UNION '+
3854 ' Select RDB$GENERATOR_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 14 as ObjectType '+
3855 ' From RDB$GENERATORS '+
3856 ' UNION '+
3857 ' Select RDB$CHARACTER_SET_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 11 as ObjectType '+
3858 ' From RDB$CHARACTER_SETS '+
3859 ' UNION '+
3860 ' Select RDB$COLLATION_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 17 as ObjectType '+
3861 ' From RDB$COLLATIONS '+
3862 ' UNION '+
3863 ' Select RDB$PACKAGE_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 18 as ObjectType '+
3864 ' From RDB$PACKAGES '+
3865 ') '+ GrantsBaseSelect;
3866
3867 GrantsSQL =
3868 'with ObjectOwners As ( '+
3869 'Select RDB$RELATION_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 0 as ObjectType '+
3870 'From RDB$RELATIONS '+
3871 'UNION '+
3872 'Select RDB$PROCEDURE_NAME as METAOBJECTNAME, RDB$OWNER_NAME, 5 as ObjectType '+
3873 'From RDB$PROCEDURES '+
3874 'UNION '+
3875 'Select RDB$EXCEPTION_NAME as METAOBJECTNAME, ''SYSDBA'', 7 as ObjectType '+
3876 'From RDB$EXCEPTIONS '+
3877 'UNION '+
3878 'Select RDB$GENERATOR_NAME as METAOBJECTNAME, ''SYSDBA'', 14 as ObjectType '+
3879 'From RDB$GENERATORS '+
3880 'UNION '+
3881 'Select RDB$CHARACTER_SET_NAME as METAOBJECTNAME, ''SYSDBA'', 11 as ObjectType '+
3882 'From RDB$CHARACTER_SETS '+
3883 ') '+ GrantsBaseSelect;
3884
3885 var qryOwnerPriv : TIBSQL;
3886
3887 begin
3888 if MetaObject = '' then
3889 exit;
3890
3891 qryOwnerPriv := TIBSQL.Create(FDatabase);
3892 try
3893 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION12 then
3894 qryOwnerPriv.SQL.Text := GrantsSQL12
3895 else
3896 qryOwnerPriv.SQL.Text := GrantsSQL;
3897 qryOwnerPriv.Params.ByName('METAOBJECTNAME').AsString := MetaObject;
3898 qryOwnerPriv.ExecQuery;
3899 while not qryOwnerPriv.Eof do
3900 begin
3901 if not NoUserGrants or (qryOwnerPriv.FieldByName('RDB$USER_TYPE').AsInteger <> obj_user)
3902 or (qryOwnerPriv.FieldByName('RDB$USER').AsString = 'PUBLIC') then
3903 begin
3904 if qryOwnerPriv.FieldByName('GRANTEDBY').IsNull then
3905 ExtractOut(Format('GRANT %s ON %s %s TO %s %s %s %s', [
3906 TrimRight(qryOwnerPriv.FieldByName('Privileges').AsString),
3907 TrimRight(qryOwnerPriv.FieldByName('OBJECT_TYPE_NAME').AsString),
3908 QuoteIdentifier(TrimRight(qryOwnerPriv.FieldByName('METAOBJECTNAME').AsString)),
3909 Trim(qryOwnerPriv.FieldByName('USER_TYPE_NAME').AsString),
3910 QuoteIdentifier(TrimRight(qryOwnerPriv.FieldByName('RDB$USER').AsString)),
3911 TrimRight(qryOwnerPriv.FieldByName('GRANTOPTION').AsString),
3912 Terminator]))
3913 else
3914 ExtractOut(Format('GRANT %s ON %s %s TO %s %s %s GRANTED BY %s %s', [
3915 TrimRight(qryOwnerPriv.FieldByName('Privileges').AsString),
3916 TrimRight(qryOwnerPriv.FieldByName('OBJECT_TYPE_NAME').AsString),
3917 QuoteIdentifier(TrimRight(qryOwnerPriv.FieldByName('METAOBJECTNAME').AsString)),
3918 TrimRight(qryOwnerPriv.FieldByName('USER_TYPE_NAME').AsString),
3919 QuoteIdentifier(TrimRight(qryOwnerPriv.FieldByName('RDB$USER').AsString)),
3920 TrimRight(qryOwnerPriv.FieldByName('GRANTOPTION').AsString),
3921 QuoteIdentifier(TrimRight(qryOwnerPriv.FieldByName('GRANTEDBY').AsString)),
3922 Terminator]));
3923 end;
3924 qryOwnerPriv.Next;
3925 end;
3926 qryOwnerPriv.Close;
3927 finally
3928 qryOwnerPriv.Free;
3929 end;
3930 end;
3931
3932 procedure TIBExtract.ShowGrantsTo(MetaObject: String; ObjectType: integer; Terminator: String);
3933 const
3934 GrantsSQL =
3935 'Select Trim(RDB$USER) as RDB$USER,List("Privileges") as Privileges, '+
3936 'coalesce(RDB$GRANT_OPTION,0) as RDB$GRANT_OPTION,METAOBJECTNAME, '+
3937 'RDB$USER_TYPE, RDB$OBJECT_TYPE, '+
3938 'case RDB$OBJECT_TYPE '+
3939 'When 0 then ''TABLE'' '+
3940 'When 5 then ''PROCEDURE'' '+
3941 'When 7 then ''EXCEPTION'' '+
3942 'When 11 then ''CHARACTER SET'' '+
3943 'ELSE NULL END as OBJECT_TYPE_NAME, '+
3944 'case RDB$USER_TYPE '+
3945 'When 5 then ''PROCEDURE'' '+
3946 'When 2 then ''TRIGGER'' '+
3947 'When 8 then ''USER'' '+
3948 'When 13 then ''ROLE'' '+
3949 'ELSE NULL END as USER_TYPE_NAME, '+
3950 'case '+
3951 'When coalesce(RDB$GRANT_OPTION,0) <> 0 and RDB$USER_TYPE = 13 then '' WITH ADMIN OPTION'' '+
3952 'When coalesce(RDB$GRANT_OPTION,0) <> 0 and RDB$USER_TYPE <> 13 then '' WITH GRANT OPTION'' '+
3953 'ELSE '''' End as GRANTOPTION '+
3954 'From ( '+
3955 'Select PR.RDB$USER,PR.RDB$RELATION_NAME as METAOBJECTNAME, LIST(DISTINCT Trim(Case PR.RDB$PRIVILEGE '+
3956 'When ''X'' then ''EXECUTE'' '+
3957 'When ''S'' then ''SELECT'' '+
3958 'When ''U'' then ''UPDATE'' '+
3959 'When ''D'' then ''DELETE'' '+
3960 'When ''R'' then ''REFERENCES'' '+
3961 'When ''G'' then ''USAGE'' '+
3962 'When ''I'' then ''INSERT'' end )) as "Privileges", '+
3963 'PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE '+
3964 'FROM RDB$USER_PRIVILEGES PR '+
3965 'Where PR.RDB$PRIVILEGE <> ''M'' and (PR.RDB$PRIVILEGE <> ''U'' or PR.RDB$FIELD_NAME is null) '+
3966 'Group By PR.RDB$USER,PR.RDB$RELATION_NAME,PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE '+
3967 'UNION '+
3968 'Select PR.RDB$USER,PR.RDB$RELATION_NAME, ''Update('' || List(Trim(PR.RDB$FIELD_NAME)) || '')'', '+
3969 'PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE '+
3970 'FROM RDB$USER_PRIVILEGES PR '+
3971 'Where PR.RDB$PRIVILEGE = ''U'' and PR.RDB$FIELD_NAME is not null '+
3972 'Group By PR.RDB$USER,PR.RDB$RELATION_NAME,PR.RDB$GRANT_OPTION, PR.RDB$USER_TYPE, PR.RDB$OBJECT_TYPE) '+
3973 'Where RDB$USER = :METAOBJECTNAME and RDB$USER_TYPE = :USERTYPE '+
3974 'Group By RDB$USER,RDB$GRANT_OPTION, RDB$USER_TYPE, RDB$OBJECT_TYPE, METAOBJECTNAME '+
3975 'ORDER BY METAOBJECTNAME';
3976
3977 var qryOwnerPriv : TIBSQL;
3978
3979 begin
3980 if MetaObject = '' then
3981 exit;
3982
3983 qryOwnerPriv := TIBSQL.Create(FDatabase);
3984 try
3985 qryOwnerPriv.SQL.Text := GrantsSQL;
3986 qryOwnerPriv.Params.ByName('METAOBJECTNAME').AsString := MetaObject;
3987 qryOwnerPriv.Params.ByName('USERTYPE').AsInteger := ObjectType;
3988 qryOwnerPriv.ExecQuery;
3989 while not qryOwnerPriv.Eof do
3990 begin
3991 ExtractOut(Format('GRANT %s ON %s %s TO %s %s %s%s', [
3992 TrimRight(qryOwnerPriv.FieldByName('Privileges').AsString),
3993 TrimRight(qryOwnerPriv.FieldByName('OBJECT_TYPE_NAME').AsString),
3994 QuoteIdentifier(TrimRight(qryOwnerPriv.FieldByName('METAOBJECTNAME').AsString)),
3995 TrimRight(qryOwnerPriv.FieldByName('USER_TYPE_NAME').AsString),
3996 QuoteIdentifier(TrimRight(qryOwnerPriv.FieldByName('RDB$USER').AsString)),
3997 TrimRight(qryOwnerPriv.FieldByName('GRANTOPTION').AsString),
3998 Terminator]));
3999 qryOwnerPriv.Next;
4000 end;
4001 qryOwnerPriv.Close;
4002 finally
4003 qryOwnerPriv.Free;
4004 end;
4005 ExtractOut('');
4006 end;
4007
4008 { ShowGrantRoles
4009 Functional description
4010 Show grants for given role name
4011 This function is also called by extract for privileges.
4012 All membership privilege may have the with_admin option set. }
4013
4014 procedure TIBExtract.ShowGrantRoles(Terminator: String);
4015 const
4016 RoleSQL =
4017 'SELECT * FROM RDB$USER_PRIVILEGES ' +
4018 'WHERE ' +
4019 ' RDB$OBJECT_TYPE = %d AND ' +
4020 ' RDB$USER_TYPE = %d AND ' +
4021 ' RDB$PRIVILEGE = ''M'' AND RDB$USER <> ''SYSDBA''' +
4022 'ORDER BY RDB$RELATION_NAME, RDB$USER';
4023
4024 var
4025 IsDefault, WithOption, UserString : String;
4026 qryRole : TIBSQL;
4027
4028 begin
4029 qryRole := TIBSQL.Create(FDatabase);
4030 try
4031 qryRole.SQL.Text := Format(RoleSQL, [obj_sql_role, obj_user]);
4032 qryRole.ExecQuery;
4033 while not qryRole.Eof do
4034 begin
4035 UserString := Trim(qryRole.FieldByName('RDB$USER').AsString);
4036
4037 if (not qryRole.FieldByName('RDB$GRANT_OPTION').IsNull) and
4038 (qryRole.FieldByName('RDB$GRANT_OPTION').AsInteger = 1) then
4039 WithOption := ' WITH ADMIN OPTION'
4040 else
4041 WithOption := '';
4042 {DEFAULT added in Firebird 4}
4043 if qryRole.HasField('RDB$FIELD_NAME') and (qryRole.FieldByName('RDB$FIELD_NAME').AsString = 'D') then
4044 IsDefault := 'DEFAULT '
4045 else
4046 IsDefault := '';
4047 ExtractOut(Format('GRANT %s%s TO %s%s%s%s',
4048 [ IsDefault, QuoteIdentifier(TrimRight(qryRole.FieldByName('RDB$RELATION_NAME').AsString)),
4049 UserString, WithOption, Terminator, LineEnding]));
4050
4051 qryRole.Next;
4052 end;
4053 finally
4054 qryRole.Free;
4055 end;
4056 end;
4057
4058 { GetProcedureArgs
4059 Functional description
4060 This function extract the procedure parameters and adds it to the
4061 extract file }
4062
4063 procedure TIBExtract.GetProcedureArgs(Proc: String);
4064 const
4065 { query to retrieve the input parameters. }
4066 ProcHeaderSQL =
4067 'SELECT * ' +
4068 ' FROM RDB$PROCEDURE_PARAMETERS PRM JOIN RDB$FIELDS FLD ON ' +
4069 ' PRM.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME ' +
4070 'WHERE ' +
4071 ' PRM.RDB$PROCEDURE_NAME = :PROCNAME AND ' +
4072 ' PRM.RDB$PARAMETER_TYPE = :Input ' +
4073 'ORDER BY PRM.RDB$PARAMETER_NUMBER';
4074
4075 var
4076 FirstTime : Boolean;
4077 Line : String;
4078 qryHeader : TIBSQL;
4079
4080 function FormatParamStr : String;
4081 begin
4082 Result := Format(' %s ', [TrimRight(qryHeader.FieldByName('RDB$PARAMETER_NAME').AsString)]) +
4083 GetFieldType(qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger,
4084 qryHeader.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger,
4085 qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger,
4086 qryHeader.FieldByName('RDB$FIELD_PRECISION').AsInteger,
4087 qryHeader.FieldByName('RDB$FIELD_LENGTH').AsInteger,
4088 not qryHeader.FieldByName('RDB$CHARACTER_SET_ID').IsNull,
4089 true,
4090 qryHeader.FieldByName('RDB$CHARACTER_SET_ID').AsInteger,
4091 qryHeader.FieldByName('RDB$CHARACTER_LENGTH').AsInteger,
4092 qryHeader.FieldByName('RDB$SEGMENT_LENGTH').AsInteger);
4093
4094 if qryHeader.FieldByName('RDB$NULL_FLAG').AsInteger = 1 then
4095 Result := Result + ' NOT NULL';
4096
4097 if not qryHeader.FieldByName('RDB$CHARACTER_SET_ID').IsNull and
4098 not qryHeader.FieldByName('RDB$COLLATION_ID').IsNull then
4099 Result := Result + GetCollationName(qryHeader.FieldByName('RDB$CHARACTER_SET_ID').AsInteger,
4100 qryHeader.FieldByName('RDB$COLLATION_ID').AsInteger);
4101
4102 if not qryHeader.FieldByName('RDB$DEFAULT_SOURCE').IsNull then
4103 Result := Result + ' = ' + qryHeader.FieldByName('RDB$DEFAULT_SOURCE').AsString;
4104
4105 end;
4106
4107 begin
4108 FirstTime := true;
4109 qryHeader := TIBSQL.Create(FDatabase);
4110 try
4111 qryHeader.SQL.Text := ProcHeaderSQL;
4112 qryHeader.Params.ByName('procname').AsString := Proc;
4113 qryHeader.Params.ByName('Input').AsInteger := 0;
4114 qryHeader.ExecQuery;
4115 while not qryHeader.Eof do
4116 begin
4117 if FirstTime then
4118 begin
4119 FirstTime := false;
4120 ExtractOut('(');
4121 end;
4122
4123 Line := FormatParamStr;
4124
4125 qryHeader.Next;
4126 if not qryHeader.Eof then
4127 Line := Line + ',';
4128 ExtractOut(Line);
4129 end;
4130
4131 { If there was at least one param, close parens }
4132 if not FirstTime then
4133 begin
4134 ExtractOut( ')');
4135 end;
4136
4137 FirstTime := true;
4138 qryHeader.Close;
4139 qryHeader.Params.ByName('Input').AsInteger := 1;
4140 qryHeader.ExecQuery;
4141
4142 while not qryHeader.Eof do
4143 begin
4144 if FirstTime then
4145 begin
4146 FirstTime := false;
4147 ExtractOut('RETURNS' + LineEnding + '(');
4148 end;
4149
4150 Line := FormatParamStr;
4151
4152 qryHeader.Next;
4153 if not qryHeader.Eof then
4154 Line := Line + ',';
4155 ExtractOut(Line);
4156 end;
4157
4158 { If there was at least one param, close parens }
4159 if not FirstTime then
4160 begin
4161 ExtractOut( ')');
4162 end;
4163
4164 ExtractOut('AS');
4165 finally
4166 qryHeader.Free;
4167 end;
4168 end;
4169
4170 procedure TIBExtract.Notification(AComponent: TComponent;
4171 Operation: TOperation);
4172 begin
4173 inherited;
4174 if (AComponent = FDatabase) and (Operation = opRemove) then
4175 FDatabase := nil;
4176 if (AComponent = FTransaction) and (Operation = opRemove) then
4177 FTransaction := nil;
4178 end;
4179
4180 function TIBExtract.QuoteIdentifier(Value: String): String;
4181 begin
4182 if AlwaysQuoteIdentifiers then
4183 Result := IBUtils.QuoteIdentifier(FDatabase.DBSQLDialect,Value)
4184 else
4185 Result := IBUtils.QuoteIdentifierIfNeeded(FDatabase.DBSQLDialect,Value)
4186 end;
4187
4188 function TIBExtract.GetFieldType(qry: TIBSQL; ForceCharSet: boolean
4189 ): string;
4190 var DomainName: string;
4191 begin
4192 DomainName := qry.FieldByName('RDB$FIELD_SOURCE').AsString;
4193 if not ((length(DomainName) > 4) and (system.Copy(DomainName, 1, 4) = 'RDB$') and (DomainName[5] in ['0'..'9'])) and
4194 (qry.FieldByName('RDB$SYSTEM_FLAG').AsInteger <> 1) then
4195 begin
4196 {Must be a domain name}
4197 Result := QuoteIdentifier(trim(DomainName));
4198
4199 { International character sets }
4200 if (qry.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_text, blr_varying])
4201 and (not qry.FieldByName('RDB$COLLATION_ID').IsNull)
4202 and (qry.FieldByName('RDB$COLLATION_ID').AsInteger <> 0) then
4203 Result := Result + GetCharacterSets(qry.FieldByName('RDB$CHARACTER_SET_ID').AsShort,
4204 qry.FieldByName('RDB$COLLATION_ID').AsInteger, true);
4205 end
4206 else
4207 Result := GetFieldType(qry.FieldByName('RDB$FIELD_TYPE').AsInteger,
4208 qry.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger,
4209 qry.FieldByName('RDB$FIELD_SCALE').AsInteger,
4210 qry.FieldByName('RDB$FIELD_PRECISION').AsInteger,
4211 qry.FieldByName('RDB$FIELD_LENGTH').AsInteger,
4212 not qry.FieldByName('RDB$CHARACTER_SET_ID').IsNull,
4213 ForceCharSet,
4214 qry.FieldByName('RDB$CHARACTER_SET_ID').AsInteger,
4215 qry.FieldByName('RDB$CHARACTER_LENGTH').AsInteger,
4216 qry.FieldByName('RDB$SEGMENT_LENGTH').AsInteger,
4217 not qry.FieldByName('RDB$DIMENSIONS').IsNull and (qry.FieldByName('RDB$DIMENSIONS').AsInteger <> 0),
4218 DomainName);
4219 end;
4220
4221 procedure TIBExtract.ListData(ObjectName: String);
4222 const
4223 SelectFieldListSQL = 'Select List(RDB$FIELD_NAME) From ( '+
4224 'Select RF.RDB$FIELD_NAME From RDB$RELATION_FIELDS RF '+
4225 'JOIN RDB$FIELDS F On F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE '+
4226 'Where F.RDB$COMPUTED_BLR is NULL and RF.RDB$RELATION_NAME = Upper(:Relation) '+
4227 'Order by RF.RDB$FIELD_POSITION asc)';
4228
4229 TableSQL =
4230 'SELECT * FROM RDB$RELATIONS ' +
4231 'WHERE ' +
4232 ' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' +
4233 ' RDB$VIEW_BLR IS NULL ' +
4234 'ORDER BY RDB$RELATION_NAME';
4235
4236 var FieldList: string;
4237
4238 begin
4239 if ObjectName = '' then {List all}
4240 begin
4241 with TIBSQL.Create(self) do
4242 try
4243 Database := FDatabase;
4244 SQL.Text := TableSQL;
4245 ExecQuery;
4246 ExtractOut('/* Data Starts */');
4247 while not EOF do
4248 begin
4249 ListData(Trim(FieldByName('RDB$RELATION_NAME').AsString));
4250 Next;
4251 end;
4252 ExtractOut('/* Data Ends */');
4253 finally
4254 Free;
4255 end;
4256 end
4257 else
4258 begin
4259 FieldList := '*';
4260 with TIBSQL.Create(self) do
4261 try
4262 Database := FDatabase;
4263 SQL.Text := SelectFieldListSQL;
4264 Params[0].AsString := ObjectName;
4265 ExecQuery;
4266 try
4267 if not EOF then
4268 FieldList := TrimRight(Fields[0].AsString);
4269 finally
4270 Close;
4271 end;
4272 finally
4273 Free
4274 end;
4275
4276 with TIBInsertStmtsOut.Create(self) do
4277 try
4278 Database := FDatabase;
4279 if DataOut(Format('Select %s From %s',[FieldList,QuoteIdentifier( TrimRight(ObjectName))]),
4280 Add2MetaData) then
4281 ExtractOut('COMMIT;');
4282 finally
4283 Free
4284 end;
4285 end;
4286 end;
4287
4288 procedure TIBExtract.ListRoles(ObjectName: String; IncludeGrants: boolean);
4289 const
4290 RolesSQL =
4291 'select * from RDB$ROLES WHERE RDB$SYSTEM_FLAG = 0 ' +
4292 'order by RDB$ROLE_NAME';
4293
4294 RolesByNameSQL =
4295 'select * from RDB$ROLES ' +
4296 'WHERE RDB$ROLE_NAME = :RoleName ' +
4297 'order by RDB$ROLE_NAME';
4298
4299 var
4300 qryRoles : TIBSQL;
4301 PrevOwner, RoleName, OwnerName : String;
4302 Comments: TStrings;
4303 sPrivileges: string;
4304 Privileges: cardinal;
4305 i: integer;
4306 begin
4307 {Process GRANT roles}
4308 Comments := TStringList.Create;
4309 qryRoles := TIBSQL.Create(FDatabase);
4310 try
4311 if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION9 then
4312 begin
4313 PrevOwner := '';
4314 ExtractOut('');
4315 ExtractOut('/* Grant Roles for this database */');
4316 ExtractOut('');
4317
4318 if ObjectName = '' then
4319 qryRoles.SQL.Text := RolesSQL
4320 else
4321 begin
4322 qryRoles.SQL.Text := RolesByNameSQL;
4323 qryRoles.Params.ByName('RoleName').AsString := ObjectName;
4324 end;
4325 qryRoles.ExecQuery;
4326 try
4327 while not qryRoles.Eof do
4328 begin
4329 AddComment(qryRoles,ctRole,Comments);
4330 RoleName := QuoteIdentifier(
4331 qryRoles.FieldByName('rdb$Role_Name').AsString);
4332 OwnerName := Trim(qryRoles.FieldByName('rdb$Owner_Name').AsString);
4333 if PrevOwner <> OwnerName then
4334 begin
4335 ExtractOut('');
4336 ExtractOut(Format('/* Role: %s, Owner: %s */', [RoleName, OwnerName]));
4337 ExtractOut('');
4338 PrevOwner := OwnerName;
4339 end;
4340 sPrivileges := '';
4341 if (FDatabaseInfo.ODSMajorVersion >= ODS_VERSION13) and
4342 qryRoles.HasField('RDB$SYSTEM_PRIVILEGES') then
4343 begin
4344 sPrivileges := qryRoles.FieldByName('RDB$SYSTEM_PRIVILEGES').AsString;
4345 Privileges := byte(sPrivileges[1]) shl 24 + byte(sPrivileges[2]) shl 16 +
4346 byte(sPrivileges[3]) shl 8 + byte(sPrivileges[4]);
4347 sPrivileges := '';
4348 for i := Low(UserPrivileges) to high(UserPrivileges) do
4349 if (UserPrivileges[i].Mask and Privileges) <> 0 then
4350 if sPrivileges = '' then
4351 sPrivileges := UserPrivileges[i].Privilege
4352 else
4353 sPrivileges := sPrivileges + ',' + UserPrivileges[i].Privilege;
4354 end;
4355
4356 if sPrivileges <> '' then
4357 ExtractOut('CREATE ROLE ' + RoleName + ' SET SYSTEM PRIVILEGES TO ' + sPrivileges + Term)
4358 else
4359 ExtractOut('CREATE ROLE ' + RoleName + Term);
4360
4361 if IncludeGrants then
4362 ShowGrantsTo(qryRoles.FieldByName('rdb$Role_Name').AsString,obj_sql_role,Term);
4363 qryRoles.Next;
4364 end;
4365 finally
4366 qryRoles.Close;
4367 end;
4368 ExtractOut(Comments);
4369 end;
4370 finally
4371 qryRoles.Free;
4372 Comments.Free;
4373 end;
4374 end;
4375
4376 end.
4377
4378