{************************************************************************}
{ }
{ Borland Delphi Visual Component Library }
{ InterBase Express core components }
{ }
{ Copyright (c) 1998-2001 Borland Software Corporation }
{ }
{ The contents of this file are subject to the InterBase }
{ Public License Version 1.0 (the "License"); you may not }
{ use this file except in compliance with the License. You may obtain }
{ a copy of the License at http://www.borland.com/interbase/IPL.html }
{ Software distributed under the License is distributed on }
{ an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
{ express or implied. See the License for the specific language }
{ governing rights and limitations under the License. }
{ The Original Code was created by InterBase Software Corporation }
{ and its successors. }
{ Portions created by Borland Software Corporation are Copyright }
{ (C) Borland Software Corporation. All Rights Reserved. }
{ IBX Version 4.2 or higher required }
{ Contributor(s): Jeff Overcash }
{ }
{************************************************************************}
unit IBExtract;
interface
uses
SysUtils, Classes, IBDatabase, IBDatabaseInfo,
IBSQL, IBUtils, IBHeader, IB, IBIntf, IBExternals;
type
TExtractObjectTypes =
(eoDatabase, eoDomain, eoTable, eoView, eoProcedure, eoFunction,
eoGenerator, eoException, eoBLOBFilter, eoRole, eoTrigger, eoForeign,
eoIndexes, eoChecks, eoData);
TExtractType =
(etDomain, etTable, etRole, etTrigger, etForeign,
etIndex, etData, etGrant, etCheck, etAlterProc);
TExtractTypes = Set of TExtractType;
TIBExtract = class(TComponent)
private
FDatabase : TIBDatabase;
FTransaction : TIBTransaction;
FMetaData: TStrings;
FDatabaseInfo: TIBDatabaseInfo;
FShowSystem: Boolean;
{ Private declarations }
function GetDatabase: TIBDatabase;
function GetIndexSegments ( indexname : String) : String;
function GetTransaction: TIBTransaction;
procedure SetDatabase(const Value: TIBDatabase);
procedure SetTransaction(const Value: TIBTransaction);
function PrintValidation(ToValidate : String; flag : Boolean) : String;
procedure ShowGrants(MetaObject: String; Terminator : String);
procedure ShowGrantRoles(Terminator : String);
procedure GetProcedureArgs(Proc : String);
function GetFieldLength(sql : TIBSQL) : Integer;
function CreateIBSQL : TIBSQL;
protected
function ExtractDDL(Flag : Boolean; TableName : String) : Boolean;
function ExtractListTable(RelationName, NewName : String; DomainFlag : Boolean) : Boolean;
procedure ExtractListView (ViewName : String);
procedure ListData(ObjectName : String);
procedure ListRoles(ObjectName : String = ''); {do not localize}
procedure ListGrants;
procedure ListProcs(ProcedureName : String = ''; AlterOnly : Boolean = false); {do not localize}
procedure ListAllTables(flag : Boolean);
procedure ListTriggers(ObjectName : String = ''; ExtractType : TExtractType = etTrigger); {do not localize}
procedure ListCheck(ObjectName : String = ''; ExtractType : TExtractType = etCheck); {do not localize}
function PrintSet(var Used : Boolean) : String;
procedure ListCreateDb(TargetDb : String = ''); {do not localize}
procedure ListDomains(ObjectName : String = ''; ExtractType : TExtractType = etDomain); {do not localize}
procedure ListException(ExceptionName : String = ''); {do not localize}
procedure ListFilters(FilterName : String = ''); {do not localize}
procedure ListForeign(ObjectName : String = ''; ExtractType : TExtractType = etForeign); {do not localize}
procedure ListFunctions(FunctionName : String = ''); {do not localize}
procedure ListGenerators(GeneratorName : String = ''); {do not localize}
procedure ListIndex(ObjectName : String = ''; ExtractType : TExtractType = etIndex); {do not localize}
procedure ListViews(ViewName : String = ''); {do not localize}
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
function GetArrayField(FieldName : String) : String;
function GetFieldType(FieldType, FieldSubType, FieldScale, FieldSize,
FieldPrec, FieldLen : Integer) : String;
function GetCharacterSets(CharSetId, Collation : Short; CollateOnly : Boolean) : String;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure ExtractObject(ObjectType : TExtractObjectTypes; ObjectName : String = ''; {do not localize}
ExtractTypes : TExtractTypes = []);
property DatabaseInfo : TIBDatabaseInfo read FDatabaseInfo;
property Items : TStrings read FMetaData;
published
{ Published declarations }
property Database : TIBDatabase read GetDatabase write SetDatabase;
property Transaction : TIBTransaction read GetTransaction write SetTransaction;
property ShowSystem: Boolean read FShowSystem write FShowSystem;
end;
TSQLType = record
SqlType : Integer;
TypeName : String;
end;
TPrivTypes = record
PrivFlag : Integer;
PrivString : String;
end;
TSQLTypes = Array[0..13] of TSQLType;
const
priv_UNKNOWN = 1;
priv_SELECT = 2;
priv_INSERT = 4;
priv_UPDATE = 8;
priv_DELETE = 16;
priv_EXECUTE = 32;
priv_REFERENCES = 64;
PrivTypes : Array[0..5] of TPrivTypes = (
(PrivFlag : priv_DELETE; PrivString : 'DELETE' ), {do not localize}
(PrivFlag : priv_EXECUTE; PrivString : 'EXECUTE' ), {do not localize}
(PrivFlag : priv_INSERT; PrivString : 'INSERT' ), {do not localize}
(PrivFlag : priv_SELECT; PrivString : 'SELECT' ), {do not localize}
(PrivFlag : priv_UPDATE; PrivString : 'UPDATE' ), {do not localize}
(PrivFlag : priv_REFERENCES; PrivString : 'REFERENCES')); {do not localize}
ColumnTypes : TSQLTypes = (
(SqlType : blr_short; TypeName : 'SMALLINT'), {do not localize}
(SqlType : blr_long; TypeName : 'INTEGER'), {do not localize}
(SqlType : blr_quad; TypeName : 'QUAD'), {do not localize}
(SqlType : blr_float; TypeName : 'FLOAT'), {do not localize}
(SqlType : blr_text; TypeName : 'CHAR'), {do not localize}
(SqlType : blr_double; TypeName : 'DOUBLE PRECISION'), {do not localize}
(SqlType : blr_varying; TypeName : 'VARCHAR'), {do not localize}
(SqlType : blr_cstring; TypeName : 'CSTRING'), {do not localize}
(SqlType : blr_blob_id; TypeName : 'BLOB_ID'), {do not localize}
(SqlType : blr_blob; TypeName : 'BLOB'), {do not localize}
(SqlType : blr_sql_time; TypeName : 'TIME'), {do not localize}
(SqlType : blr_sql_date; TypeName : 'DATE'), {do not localize}
(SqlType : blr_timestamp; TypeName : 'TIMESTAMP'), {do not localize}
(SqlType : blr_int64; TypeName : 'INT64')); {do not localize}
SubTypes : Array[0..8] of String = (
'UNKNOWN', {do not localize}
'TEXT', {do not localize}
'BLR', {do not localize}
'ACL', {do not localize}
'RANGES', {do not localize}
'SUMMARY', {do not localize}
'FORMAT', {do not localize}
'TRANSACTION_DESCRIPTION', {do not localize}
'EXTERNAL_FILE_DESCRIPTION'); {do not localize}
TriggerTypes : Array[0..6] of String = (
'', {do not localize}
'BEFORE INSERT', {do not localize}
'AFTER INSERT', {do not localize}
'BEFORE UPDATE', {do not localize}
'AFTER UPDATE', {do not localize}
'BEFORE DELETE', {do not localize}
'AFTER DELETE'); {do not localize}
IntegralSubtypes : Array[0..2] of String = (
'UNKNOWN', {do not localize}
'NUMERIC', {do not localize}
'DECIMAL'); {do not localize}
ODS_VERSION6 = 6; { on-disk structure as of v3.0 }
ODS_VERSION7 = 7; { new on disk structure for fixing index bug }
ODS_VERSION8 = 8; { new btree structure to support pc semantics }
ODS_VERSION9 = 9; { btree leaf pages are always propogated up }
ODS_VERSION10 = 10; { V6.0 features. SQL delimited idetifier,
SQLDATE, and 64-bit exact numeric
type }
{ flags for RDB$FILE_FLAGS }
FILE_shadow = 1;
FILE_inactive = 2;
FILE_manual = 4;
FILE_cache = 8;
FILE_conditional = 16;
{ flags for RDB$LOG_FILES }
LOG_serial = 1;
LOG_default = 2;
LOG_raw = 4;
LOG_overflow = 8;
MAX_INTSUBTYPES = 2;
MAXSUBTYPES = 8; { Top of subtypes array }
{ Object types used in RDB$DEPENDENCIES and RDB$USER_PRIVILEGES }
obj_relation = 0;
obj_view = 1;
obj_trigger = 2;
obj_computed = 3;
obj_validation = 4;
obj_procedure = 5;
obj_expression_index = 6;
obj_exception = 7;
obj_user = 8;
obj_field = 9;
obj_index = 10;
obj_count = 11;
obj_user_group = 12;
obj_sql_role = 13;
implementation
const
NEWLINE = #13#10; {do not localize}
TERM = ';'; {do not localize}
ProcTerm = '^'; {do not localize}
CollationSQL =
'SELECT CST.RDB$CHARACTER_SET_NAME, COL.RDB$COLLATION_NAME, CST.RDB$DEFAULT_COLLATE_NAME ' + {do not localize}
'FROM RDB$COLLATIONS COL JOIN RDB$CHARACTER_SETS CST ON ' + {do not localize}
' COL.RDB$CHARACTER_SET_ID = CST.RDB$CHARACTER_SET_ID ' + {do not localize}
'WHERE ' + {do not localize}
' COL.RDB$COLLATION_ID = :COLLATION AND ' + {do not localize}
' CST.RDB$CHARACTER_SET_ID = :CHAR_SET_ID ' + {do not localize}
'ORDER BY COL.RDB$COLLATION_NAME, CST.RDB$CHARACTER_SET_NAME'; {do not localize}
NonCollationSQL =
'SELECT CST.RDB$CHARACTER_SET_NAME ' + {do not localize}
'FROM RDB$CHARACTER_SETS CST ' + {do not localize}
'WHERE CST.RDB$CHARACTER_SET_ID = :CHARSETID ' + {do not localize}
'ORDER BY CST.RDB$CHARACTER_SET_NAME'; {do not localize}
PrecisionSQL =
'SELECT * FROM RDB$FIELDS ' + {do not localize}
'WHERE RDB$FIELD_NAME = :FIELDNAME'; {do not localize}
ArraySQL =
'SELECT * FROM RDB$FIELD_DIMENSIONS FDIM ' + {do not localize}
'WHERE ' + {do not localize}
' FDIM.RDB$FIELD_NAME = :FIELDNAME ' + {do not localize}
'ORDER BY FDIM.RDB$DIMENSION'; {do not localize}
{ TIBExtract }
{ ArrayDimensions
Functional description
Retrieves the dimensions of arrays and prints them.
Parameters: fieldname -- the actual name of the array field }
function TIBExtract.GetArrayField(FieldName: String): String;
var
qryArray : TIBSQL;
begin
qryArray := CreateIBSQL;
Result := '['; {do not localize}
qryArray.SQL.Add(ArraySQL);
qryArray.Params.ByName('FieldName').AsTrimString := FieldName; {do not localize}
qryArray.ExecQuery;
{ Format is [lower:upper, lower:upper,..] }
while not qryArray.Eof do
begin
if (qryArray.FieldByName('RDB$DIMENSION').AsInteger > 0) then {do not localize}
Result := Result + ', '; {do not localize}
Result := Result + qryArray.FieldByName('RDB$LOWER_BOUND').AsTrimString + ':' + {do not localize}
qryArray.FieldByName('RDB$UPPER_BOUND').AsTrimString; {do not localize}
qryArray.Next;
end;
Result := Result + '] '; {do not localize}
qryArray.Free;
end;
constructor TIBExtract.Create(AOwner: TComponent);
begin
inherited;
FMetaData := TStringList.Create;
FDatabaseInfo := TIBDatabaseInfo.Create(nil);
FDatabaseInfo.Database := FDatabase;
if AOwner is TIBDatabase then
Database := TIBDatabase(AOwner);
if AOwner is TIBTransaction then
Transaction := TIBTransaction(AOwner);
end;
destructor TIBExtract.Destroy;
begin
FMetaData.Free;
FDatabasEInfo.Free;
inherited;
end;
function TIBExtract.ExtractDDL(Flag: Boolean; TableName: String) : Boolean;
var
DidConnect : Boolean;
DidStart : Boolean;
begin
Result := true;
DidConnect := false;
DidStart := false;
if not FDatabase.Connected then
begin
FDatabase.Connected := true;
didConnect := true;
end;
FMetaData.Add(Format('SET SQL DIALECT %d;', [FDatabase.SQLDialect])); {do not localize}
FMetaData.Add('');
if not FTransaction.Active then
begin
FTransaction.StartTransaction;
DidStart := true;
end;
if TableName <> '' then
begin
if not ExtractListTable(TableName, '', true) then
Result := false;
end
else
begin
ListCreateDb;
ListFilters;
ListFunctions;
ListDomains;
ListAllTables(flag);
ListIndex;
ListForeign;
ListGenerators;
ListViews;
ListCheck;
ListException;
ListProcs;
ListTriggers;
ListGrants;
end;
if DidStart then
FTransaction.Commit;
if DidConnect then
FDatabase.Connected := false;
end;
{ ExtractListTable
Functional description
Shows columns, types, info for a given table name
and text of views.
If a new_name is passed, substitute it for relation_name
relation_name -- Name of table to investigate
new_name -- Name of a new name for a replacement table
domain_flag -- extract needed domains before the table }
function TIBExtract.ExtractListTable(RelationName, NewName: String;
DomainFlag: Boolean) : Boolean;
const
TableListSQL =
'SELECT * FROM RDB$RELATIONS REL JOIN RDB$RELATION_FIELDS RFR ON ' + {Do Not Localize}
' RFR.RDB$RELATION_NAME = REL.RDB$RELATION_NAME JOIN RDB$FIELDS FLD ON ' + {do not localize}
' RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME ' + {do not localize}
'WHERE REL.RDB$RELATION_NAME = :RelationName ' + {do not localize}
'ORDER BY RFR.RDB$FIELD_POSITION, RFR.RDB$FIELD_NAME'; {do not localize}
ConstraintSQL =
'SELECT RCO.RDB$CONSTRAINT_NAME, RDB$CONSTRAINT_TYPE, RDB$RELATION_NAME, ' + {do not localize}
'RDB$DEFERRABLE, RDB$INITIALLY_DEFERRED, RDB$INDEX_NAME, RDB$TRIGGER_NAME ' + {do not localize}
'FROM RDB$RELATION_CONSTRAINTS RCO, RDB$CHECK_CONSTRAINTS CON ' + {do not localize}
'WHERE ' + {do not localize}
' CON.RDB$TRIGGER_NAME = :FIELDNAME AND ' + {do not localize}
' CON.RDB$CONSTRAINT_NAME = RCO.RDB$CONSTRAINT_NAME AND ' + {do not localize}
' RCO.RDB$CONSTRAINT_TYPE = ''NOT NULL'' AND ' + {do not localize}
' RCO.RDB$RELATION_NAME = :RELATIONNAME'; {do not localize}
RelConstraintsSQL =
'SELECT * FROM RDB$RELATION_CONSTRAINTS RELC ' + {do not localize}
'WHERE ' + {do not localize}
' (RELC.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'' OR ' + {do not localize}
' RELC.RDB$CONSTRAINT_TYPE = ''UNIQUE'') AND ' + {do not localize}
' RELC.RDB$RELATION_NAME = :RELATIONNAME ' + {do not localize}
'ORDER BY RELC.RDB$CONSTRAINT_NAME'; {do not localize}
var
Collation, CharSetId : Short;
i : Short;
ColList, Column, Constraint : String;
SubType : Short;
IntChar : Short;
qryTables, qryPrecision, qryConstraints, qryRelConstraints : TIBSQL;
PrecisionKnown, ValidRelation : Boolean;
FieldScale, FieldType : Integer;
begin
Result := true;
ColList := ''; {do not localize}
IntChar := 0;
ValidRelation := false;
if DomainFlag then
ListDomains(RelationName);
qryTables := CreateIBSQL;
qryPrecision := CreateIBSQL;
qryConstraints := CreateIBSQL;
qryRelConstraints := CreateIBSQL;
try
qryTables.SQL.Add(TableListSQL);
qryTables.Params.ByName('RelationName').AsTrimString := RelationName; {do not localize}
qryTables.ExecQuery;
qryPrecision.SQL.Add(PrecisionSQL);
qryConstraints.SQL.Add(ConstraintSQL);
qryRelConstraints.SQL.Add(RelConstraintsSQL);
if not qryTables.Eof then
begin
ValidRelation := true;
if (not qryTables.FieldByName('RDB$OWNER_NAME').IsNull) and {do not localize}
(Trim(qryTables.FieldByName('RDB$OWNER_NAME').AsTrimString) <> '') then {do not localize}
FMetaData.Add(Format('%s/* Table: %s, Owner: %s */%s', {do not localize}
[NEWLINE, RelationName,
qryTables.FieldByName('RDB$OWNER_NAME').AsTrimString, NEWLINE])); {do not localize}
if NewName <> '' then {do not localize}
FMetaData.Add(Format('CREATE TABLE %s ', [QuoteIdentifier(FDatabase.SQLDialect,NewName)])) {do not localize}
else
FMetaData.Add(Format('CREATE TABLE %s ', [QuoteIdentifier(FDatabase.SQLDialect,RelationName)])); {do not localize}
if not qryTables.FieldByName('RDB$EXTERNAL_FILE').IsNull then {do not localize}
FMetaData.Add(Format('EXTERNAL FILE %s ', {do not localize}
[QuotedStr(qryTables.FieldByName('RDB$EXTERNAL_FILE').AsTrimString)])); {do not localize}
FMetaData.Add('(');
end;
while not qryTables.Eof do
begin
Column := ' ' + QuoteIdentifier(FDatabase.SQLDialect, qryTables.FieldByName('RDB$FIELD_NAME').AsTrimString) + TAB; {do not localize}
{ Check first for computed fields, then domains.
If this is a known domain, then just print the domain rather than type
Domains won't have length, array, or blob definitions, but they
may have not null, default and check overriding their definitions }
if not qryTables.FieldByName('rdb$computed_blr').IsNull then {do not localize}
begin
Column := Column + ' COMPUTED BY '; {do not localize}
if not qryTables.FieldByName('RDB$COMPUTED_SOURCE').IsNull then {do not localize}
Column := Column + PrintValidation(qryTables.FieldByName('RDB$COMPUTED_SOURCE').AsTrimString, true); {do not localize}
end
else
begin
FieldType := qryTables.FieldByName('RDB$FIELD_TYPE').AsInteger; {do not localize}
FieldScale := qryTables.FieldByName('RDB$FIELD_SCALE').AsInteger; {do not localize}
if not ((Copy(qryTables.FieldByName('RDB$FIELD_NAME1').AsTrimString, 1, 4) = 'RDB$') and {do not localize}
(qryTables.FieldByName('RDB$FIELD_NAME1').AsTrimString[5] in ['0'..'9'])) and {do not localize}
(qryTables.FieldByName('RDB$SYSTEM_FLAG').AsInteger <> 1) then {do not localize}
begin
Column := Column + QuoteIdentifier(FDatabase.SQLDialect, qryTables.FieldByName('RDB$FIELD_NAME1').AsTrimString); {do not localize}
{ International character sets }
if (qryTables.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_text, blr_varying]) {do not localize}
and (not qryTables.FieldByName('RDB$COLLATION_ID').IsNull) {do not localize}
and (qryTables.FieldByName('RDB$COLLATION_ID').AsShort <> 0) then {do not localize}
intchar := 1;
end
else
begin
{ Look through types array }
for i := Low(Columntypes) to High(ColumnTypes) do
begin
PrecisionKnown := false;
if qryTables.FieldByname('RDB$FIELD_TYPE').AsShort = ColumnTypes[i].SQLType then {do not localize}
begin
if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
begin
{ Handle Integral subtypes NUMERIC and DECIMAL }
if qryTables.FieldByName('RDB$FIELD_TYPE').AsShort in {do not localize}
[blr_short, blr_long, blr_int64] then
begin
qryPrecision.Params.ByName('FIELDNAME').AsTrimString := {do not localize}
qryTables.FieldByName('RDB$FIELD_NAME1').AsTrimString; {do not localize}
qryPrecision.ExecQuery;
{ We are ODS >= 10 and could be any Dialect }
if not qryPrecision.FieldByName('RDB$FIELD_PRECISION').IsNull then {do not localize}
begin
{ We are Dialect >=3 since FIELD_PRECISION is non-NULL }
if (qryPrecision.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger > 0) and {do not localize}
(qryPrecision.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger <= MAX_INTSUBTYPES) then {do not localize}
begin
Column := column + Format('%s(%d, %d)', {do not localize}
[IntegralSubtypes[qryPrecision.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger], {do not localize}
qryPrecision.FieldByName('RDB$FIELD_PRECISION').AsInteger, {do not localize}
-qryPrecision.FieldByName('RDB$FIELD_SCALE').AsInteger]); {do not localize}
PrecisionKnown := TRUE;
end;
end;
qryPrecision.Close;
end;
end;
if PrecisionKnown = FALSE then
begin
{ Take a stab at numerics and decimals }
if (FieldType = blr_short) and (FieldScale < 0) then
Column := Column + Format('NUMERIC(4, %d)', [-FieldScale]) {do not localize}
else
if (FieldType = blr_long) and (FieldScale < 0) then
Column := Column + Format('NUMERIC(9, %d)', [-FieldScale]) {do not localize}
else
if (FieldType = blr_double) and (FieldScale < 0) then
Column := Column + Format('NUMERIC(15, %d)', [-FieldScale]) {do not localize}
else
Column := Column + ColumnTypes[i].TypeName;
end;
end;
end;
if FieldType in [blr_text, blr_varying] then
Column := Column + Format('(%d)', [GetFieldLength(qryTables)]); {do not localize}
{ Catch arrays after printing the type }
if not qryTables.FieldByName('RDB$DIMENSIONS').IsNull then {do not localize}
Column := column + GetArrayField(qryTables.FieldByName('RDB$FIELD_NAME1').AsTrimString); {do not localize}
if FieldType = blr_blob then
begin
subtype := qryTables.FieldByName('RDB$FIELD_SUB_TYPE').AsShort; {do not localize}
Column := Column + ' SUB_TYPE '; {do not localize}
if (subtype > 0) and (subtype <= MAXSUBTYPES) then
Column := Column + SubTypes[subtype]
else
Column := Column + IntToStr(subtype);
column := Column + Format(' SEGMENT SIZE %d', {do not localize}
[qryTables.FieldByName('RDB$SEGMENT_LENGTH').AsInteger]); {do not localize}
end;
{ International character sets }
if ((FieldType in [blr_text, blr_varying]) or
(FieldType = blr_blob)) and
(not qryTables.FieldByName('RDB$CHARACTER_SET_ID').IsNull) and {do not localize}
(qryTables.FieldByName('RDB$CHARACTER_SET_ID').AsInteger <> 0) then {do not localize}
begin
{ Override rdb$fields id with relation_fields if present }
CharSetId := 0;
if not qryTables.FieldByName('RDB$CHARACTER_SET_ID').IsNull then {do not localize}
CharSetId := qryTables.FieldByName('RDB$CHARACTER_SET_ID').AsInteger; {do not localize}
Column := Column + GetCharacterSets(CharSetId, 0, false);
intchar := 1;
end;
end;
{ Handle defaults for columns }
{ Originally This called PrintMetadataTextBlob,
should no longer need }
if not qryTables.FieldByName('RDB$DEFAULT_SOURCE').IsNull then {do not localize}
Column := Column + ' ' + qryTables.FieldByName('RDB$DEFAULT_SOURCE').AsTrimString; {do not localize}
{ The null flag is either 1 or null (for nullable) . if there is
a constraint name, print that too. Domains cannot have named
constraints. The column name is in rdb$trigger_name in
rdb$check_constraints. We hope we get at most one row back. }
if qryTables.FieldByName('RDB$NULL_FLAG').AsInteger = 1 then {do not localize}
begin
qryConstraints.Params.ByName('FIELDNAME').AsTrimString := qryTables.FieldByName('RDB$FIELD_NAME').AsTrimString; {do not localize}
qryConstraints.Params.ByName('RELATIONNAME').AsTrimString := qryTables.FieldByName('RDB$RELATION_NAME').AsTrimString; {do not localize}
qryConstraints.ExecQuery;
while not qryConstraints.Eof do
begin
if Pos('INTEG', qryConstraints.FieldByName('RDB$CONSTRAINT_NAME').AsTrimString) <> 1 then {do not localize}
Column := Column + Format(' CONSTRAINT %s', {do not localize}
[ QuoteIdentifier( FDatabase.SQLDialect,
qryConstraints.FieldByName('RDB$CONSTRAINT_NAME').AsTrimString)]); {do not localize}
qryConstraints.Next;
end;
qryConstraints.Close;
Column := Column + ' NOT NULL'; {do not localize}
end;
if ((FieldType in [blr_text, blr_varying]) or
(FieldType = blr_blob)) and
(not qryTables.FieldByName('RDB$CHARACTER_SET_ID').IsNull) and {do not localize}
(qryTables.FieldByName('RDB$CHARACTER_SET_ID').AsInteger <> 0) and {do not localize}
(intchar <> 0) then
begin
Collation := 0;
if not qryTables.FieldByName('RDB$COLLATION_ID1').IsNull then {do not localize}
Collation := qryTables.FieldByName('RDB$COLLATION_ID1').AsInteger {do not localize}
else
if not qryTables.FieldByName('RDB$COLLATION_ID').IsNull then {do not localize}
Collation := qryTables.FieldByName('RDB$COLLATION_ID').AsInteger; {do not localize}
CharSetId := 0;
if not qryTables.FieldByName('RDB$CHARACTER_SET_ID').IsNull then {do not localize}
CharSetId := qryTables.FieldByName('RDB$CHARACTER_SET_ID').AsInteger; {do not localize}
if Collation <> 0 then
Column := Column + GetCharacterSets(CharSetId, Collation, true);
end;
end;
qryTables.Next;
if not qryTables.Eof then
Column := Column + ','; {do not localize}
FMetaData.Add(Column);
end;
{ Do primary and unique keys only. references come later }
qryRelConstraints.Params.ByName('relationname').AsTrimString := RelationName; {do not localize}
qryRelConstraints.ExecQuery;
while not qryRelConstraints.Eof do
begin
Constraint := '';
FMetaData.Strings[FMetaData.Count - 1] := FMetaData.Strings[FMetaData.Count - 1] + ','; {do not localize}
{ If the name of the constraint is not INTEG..., print it }
if Pos('INTEG', qryRelConstraints.FieldByName('RDB$CONSTRAINT_NAME').AsTrimString) <> 1 then {do not localize}
Constraint := Constraint + 'CONSTRAINT ' + {do not localize}
QuoteIdentifier(FDatabase.SQLDialect,
qryRelConstraints.FieldByName('RDB$CONSTRAINT_NAME').AsTrimString); {do not localize}
if Pos('PRIMARY', qryRelConstraints.FieldByName('RDB$CONSTRAINT_TYPE').AsTrimString) = 1 then {do not localize}
begin
FMetaData.Add(Constraint + Format(' PRIMARY KEY (%s)', {do not localize}
[GetIndexSegments(qryRelConstraints.FieldByName('RDB$INDEX_NAME').AsTrimString)])); {do not localize}
end
else
if Pos('UNIQUE', qryRelConstraints.FieldByName('RDB$CONSTRAINT_TYPE').AsTrimString) = 1 then {do not localize}
begin
FMetaData.Add(Constraint + Format(' UNIQUE (%s)', {do not localize}
[GetIndexSegments(qryRelConstraints.FieldByName('RDB$INDEX_NAME').AsTrimString)])); {do not localize}
end;
qryRelConstraints.Next;
end;
if ValidRelation then
FMetaData.Add(')' + Term);
finally
qryTables.Free;
qryPrecision.Free;
qryConstraints.Free;
qryRelConstraints.Free;
end;
end;
{ ExtractListView
Functional description
Show text of the specified view.
Use a SQL query to get the info and print it.
Note: This should also contain check option }
procedure TIBExtract.ExtractListView(ViewName: String);
const
ViewsSQL = 'SELECT * FROM RDB$RELATIONS REL ' + {do not localize}
' WHERE ' + {do not localize}
' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' NOT REL.RDB$VIEW_BLR IS NULL AND ' + {do not localize}
' REL.RDB$RELATION_NAME = :VIEWNAME AND ' + {do not localize}
' REL.RDB$FLAGS = 1 ' + {do not localize}
'ORDER BY REL.RDB$RELATION_ID '; {do not localize}
ColumnsSQL = 'SELECT * FROM RDB$RELATION_FIELDS RFR ' + {do not localize}
'WHERE ' + {do not localize}
' RFR.RDB$RELATION_NAME = :RELATIONNAME ' + {do not localize}
'ORDER BY RFR.RDB$FIELD_POSITION '; {do not localize}
var
qryViews, qryColumns : TIBSQL;
RelationName, ColList : String;
begin
qryViews := CreateIBSQL;
qryColumns := CreateIBSQL;
try
qryViews.SQL.Add(ViewsSQL);
qryViews.Params.ByName('viewname').AsTrimString := ViewName; {do not localize}
qryViews.ExecQuery;
while not qryViews.Eof do
begin
FMetaData.Add('');
RelationName := QuoteIdentifier(FDatabase.SQLDialect,
qryViews.FieldByName('RDB$RELATION_NAME').AsTrimString); {do not localize}
FMetaData.Add(Format('%s/* View: %s, Owner: %s */%s', [ {do not localize}
RelationName,
Trim(qryViews.FieldByName('RDB$OWNER_NAME').AsTrimString)])); {do not localize}
FMetaData.Add('');
FMetaData.Add(Format('CREATE VIEW %s (', [RelationName])); {do not localize}
{ Get Column List}
qryColumns.SQL.Add(ColumnsSQL);
qryColumns.Params.ByName('relationname').AsTrimString := RelationName; {do not localize}
qryColumns.ExecQuery;
while not qryColumns.Eof do
begin
ColList := ColList + QuoteIdentifier(FDatabase.SQLDialect,
qryColumns.FieldByName('RDB$FIELD_NAME').AsTrimString); {do not localize}
qryColumns.Next;
if not qryColumns.Eof then
ColList := ColList + ', '; {do not localize}
end;
FMetaData.Add(ColList + ') AS'); {do not localize}
FMetaData.Add(qryViews.FieldByName('RDB$VIEW_SOURCE').AsTrimString + Term); {do not localize}
qryViews.Next;
end;
finally
qryViews.Free;
qryColumns.Free;
end;
end;
function TIBExtract.GetCharacterSets(CharSetId, Collation: Short;
CollateOnly: Boolean): String;
var
CharSetSQL : TIBSQL;
DidActivate : Boolean;
begin
if not FTransaction.Active then
begin
FTransaction.StartTransaction;
DidActivate := true;
end
else
DidActivate := false;
CharSetSQL := CreateIBSQL;
try
if Collation <> 0 then
begin
CharSetSQL.SQL.Add(CollationSQL);
CharSetSQL.Params.ByName('Char_Set_Id').AsInteger := CharSetId; {do not localize}
CharSetSQL.Params.ByName('Collation').AsInteger := Collation; {do not localize}
CharSetSQL.ExecQuery;
{ Is specified collation the default collation for character set? }
if (Trim(CharSetSQL.FieldByName('RDB$DEFAULT_COLLATE_NAME').AsTrimString) = {do not localize}
Trim(CharSetSQL.FieldByName('RDB$COLLATION_NAME').AsTrimString)) then {do not localize}
begin
if not CollateOnly then
Result := ' CHARACTER SET ' + Trim(CharSetSQL.FieldByName('RDB$CHARACTER_SET_NAME').AsTrimString); {do not localize}
end
else
if CollateOnly then
Result := ' COLLATE ' + Trim(CharSetSQL.FieldByName('RDB$COLLATION_NAME').AsTrimString) {do not localize}
else
Result := ' CHARACTER SET ' + {do not localize}
Trim(CharSetSQL.FieldByName('RDB$CHARACTER_SET_NAME').AsTrimString) + {do not localize}
' COLLATE ' + {do not localize}
Trim(CharSetSQL.FieldByName('RDB$COLLATION_NAME').AsTrimString); {do not localize}
end
else
if CharSetId <> 0 then
begin
CharSetSQL.SQL.Add(NonCollationSQL);
CharSetSQL.Params.ByName('CharSetId').AsShort := CharSetId; {do not localize}
CharSetSQL.ExecQuery;
Result := ' CHARACTER SET ' + Trim(CharSetSQL.FieldByName('RDB$CHARACTER_SET_NAME').AsTrimString); {do not localize}
end;
finally
CharSetSQL.Free;
end;
if DidActivate then
FTransaction.Commit;
end;
function TIBExtract.GetDatabase: TIBDatabase;
begin
result := FDatabase;
end;
{ GetIndexSegments
Functional description
returns the list of columns in an index. }
function TIBExtract.GetIndexSegments(IndexName: String): String;
const
IndexNamesSQL =
'SELECT * FROM RDB$INDEX_SEGMENTS SEG ' + {do not localize}
'WHERE SEG.RDB$INDEX_NAME = :INDEXNAME ' + {do not localize}
'ORDER BY SEG.RDB$FIELD_POSITION'; {do not localize}
var
qryColNames : TIBSQL;
begin
{ Query to get column names }
Result := '';
qryColNames := CreateIBSQL;
try
qryColNames.SQL.Add(IndexNamesSQL);
qryColNames.Params.ByName('IndexName').AsTrimString := IndexName; {do not localize}
qryColNames.ExecQuery;
while not qryColNames.Eof do
begin
{ Place a comma and a blank between each segment column name }
Result := Result + QuoteIdentifier(FDatabase.SQLDialect,
qryColNames.FieldByName('RDB$FIELD_NAME').AsTrimString); {do not localize}
qryColNames.Next;
if not qryColNames.Eof then
Result := Result + ', '; {do not localize}
end;
finally
qryColNames.Free;
end;
end;
function TIBExtract.GetTransaction: TIBTransaction;
begin
Result := FTransaction;
end;
{ ListAllGrants
Functional description
Print the permissions on all user tables.
Get separate permissions on table/views and then procedures }
procedure TIBExtract.ListGrants;
const
SecuritySQL = 'SELECT * FROM RDB$RELATIONS ' + {do not localize}
'WHERE ' + {do not localize}
' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' RDB$SECURITY_CLASS STARTING WITH ''SQL$'' ' + {do not localize}
'ORDER BY RDB$RELATION_NAME'; {do not localize}
ProcedureSQL = 'select * from RDB$PROCEDURES ' + {do not localize}
'Order BY RDB$PROCEDURE_NAME'; {do not localize}
var
qryRoles : TIBSQL;
RelationName : String;
begin
ListRoles;
qryRoles := CreateIBSQL;
try
{ This version of cursor gets only sql tables identified by security class
and misses views, getting only null view_source }
FMetaData.Add(''); {do not localize}
FMetaData.Add('/* Grant permissions for this database */'); {do not localize}
FMetaData.Add(''); {do not localize}
try
qryRoles.SQL.Text := SecuritySQL;
qryRoles.ExecQuery;
while not qryRoles.Eof do
begin
RelationName := Trim(qryRoles.FieldByName('rdb$relation_Name').AsTrimString); {do not localize}
ShowGrants(RelationName, Term);
qryRoles.Next;
end;
finally
qryRoles.Close;
end;
ShowGrantRoles(Term);
qryRoles.SQL.Text := ProcedureSQL;
qryRoles.ExecQuery;
try
while not qryRoles.Eof do
begin
ShowGrants(Trim(qryRoles.FieldByName('RDB$PROCEDURE_NAME').AsTrimString), Term); {do not localize}
qryRoles.Next;
end;
finally
qryRoles.Close;
end;
finally
qryRoles.Free;
end;
end;
{ ListAllProcs
Functional description
Shows text of a stored procedure given a name.
or lists procedures if no argument.
Since procedures may reference each other, we will create all
dummy procedures of the correct name, then alter these to their
correct form.
Add the parameter names when these procedures are created.
procname -- Name of procedure to investigate }
procedure TIBExtract.ListProcs(ProcedureName : String; AlterOnly : Boolean);
const
CreateProcedureStr1 = 'CREATE PROCEDURE %s '; {do not localize}
CreateProcedureStr2 = 'BEGIN EXIT; END %s%s'; {do not localize}
ProcedureSQL =
'SELECT * FROM RDB$PROCEDURES ' + {do not localize}
'ORDER BY RDB$PROCEDURE_NAME'; {do not localize}
ProcedureNameSQL =
'SELECT * FROM RDB$PROCEDURES ' + {do not localize}
'WHERE RDB$PROCEDURE_NAME = :ProcedureName ' + {do not localize}
'ORDER BY RDB$PROCEDURE_NAME'; {do not localize}
var
qryProcedures : TIBSQL;
ProcName : String;
SList : TStrings;
Header : Boolean;
begin
Header := true;
qryProcedures := CreateIBSQL;
SList := TStringList.Create;
try
{ First the dummy procedures
create the procedures with their parameters }
if ProcedureName = '' then
qryProcedures.SQL.Text := ProcedureSQL
else
begin
qryProcedures.SQL.Text := ProcedureNameSQL;
qryProcedures.Params.ByName('ProcedureName').AsTrimString := ProcedureName; {do not localize}
end;
if not AlterOnly then
begin
qryProcedures.ExecQuery;
while not qryProcedures.Eof do
begin
if Header then
begin
FMetaData.Add('COMMIT WORK;'); {do not localize}
FMetaData.Add('SET AUTODDL OFF;'); {do not localize}
FMetaData.Add(Format('SET TERM %s %s', [ProcTerm, Term])); {do not localize}
FMetaData.Add(Format('%s/* Stored procedures */%s', [NEWLINE, NEWLINE])); {do not localize}
Header := false;
end;
ProcName := Trim(qryProcedures.FieldByName('RDB$PROCEDURE_NAME').AsTrimString); {do not localize}
FMetaData.Add(Format(CreateProcedureStr1, [QuoteIdentifier(FDatabase.SQLDialect,
ProcName)]));
GetProcedureArgs(ProcName);
FMetaData.Add(Format(CreateProcedureStr2, [ProcTerm, NEWLINE]));
qryProcedures.Next;
end;
qryProcedures.Close;
end;
qryProcedures.ExecQuery;
while not qryProcedures.Eof do
begin
SList.Clear;
ProcName := Trim(qryProcedures.FieldByName('RDB$PROCEDURE_NAME').AsTrimString); {do not localize}
FMetaData.Add(Format('%sALTER PROCEDURE %s ', [NEWLINE, {do not localize}
QuoteIdentifier(FDatabase.SQLDialect, ProcName)]));
GetProcedureArgs(ProcName);
FMetaData.AddStrings(SList);
SList.Clear;
if not qryProcedures.FieldByName('RDB$PROCEDURE_SOURCE').IsNull then {do not localize}
begin
SList.Text := qryProcedures.FieldByName('RDB$PROCEDURE_SOURCE').AsTrimString; {do not localize}
while (Slist.Count > 0) and (Trim(SList[0]) = '') do {do not localize}
SList.Delete(0);
end;
if not AlterOnly then
SList.Add(Format(' %s%s', [ProcTerm, NEWLINE])); {do not localize}
FMetaData.AddStrings(SList);
qryProcedures.Next;
end;
{ This query gets the procedure name and the source. We then nest a query
to retrieve the parameters. Alter is used, because the procedures are
already there}
if not Header then
begin
FMetaData.Add(Format('SET TERM %s %s', [Term, ProcTerm])); {do not localize}
FMetaData.Add('COMMIT WORK;'); {do not localize}
FMetaData.Add('SET AUTODDL ON;'); {do not localize}
end;
finally
qryProcedures.Free;
SList.Free;
end;
end;
{ ListAllTables
Functional description
Extract the names of all user tables from
rdb$relations. Filter SQL tables by
security class after we fetch them
Parameters: flag -- 0, get all tables }
procedure TIBExtract.ListAllTables(flag: Boolean);
const
TableSQL =
'SELECT * FROM RDB$RELATIONS ' + {do not localize}
'WHERE ' + {do not localize}
' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' RDB$VIEW_BLR IS NULL ' + {do not localize}
'ORDER BY RDB$RELATION_NAME'; {do not localize}
var
qryTables : TIBSQL;
begin
{ This version of cursor gets only sql tables identified by security class
and misses views, getting only null view_source }
qryTables := CreateIBSQL;
try
qryTables.SQL.Text := TableSQL;
qryTables.ExecQuery;
while not qryTables.Eof do
begin
if ((qryTables.FieldByName('RDB$FLAGS').AsInteger <> 1) and {do not localize}
(not Flag)) then
continue;
if flag or (Pos('SQL$', qryTables.FieldByName('RDB$SECURITY_CLASS').AsTrimString) <> 1) then {do not localize}
ExtractListTable(qryTables.FieldByName('RDB$RELATION_NAME').AsTrimString, {do not localize}
'', false); {do not localize}
qryTables.Next;
end;
finally
qryTables.Free;
end;
end;
{ ListAllTriggers
Functional description
Lists triggers in general on non-system
tables with sql source only. }
procedure TIBExtract.ListTriggers(ObjectName : String; ExtractType : TExtractType);
const
{ Query gets the trigger info for non-system triggers with
source that are not part of an SQL constraint }
TriggerSQL =
'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$RELATIONS REL ON ' + {do not localize}
' TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME ' + {do not localize}
'WHERE ' +
' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' NOT EXISTS (SELECT * FROM RDB$CHECK_CONSTRAINTS CHK WHERE ' + {do not localize}
' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME) ' + {do not localize}
'ORDER BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, ' + {do not localize}
' TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME'; {do not localize}
TriggerNameSQL =
'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$RELATIONS REL ON ' + {do not localize}
' TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME ' + {do not localize}
'WHERE ' + {do not localize}
' REL.RDB$RELATION_NAME = :TableName AND ' + {do not localize}
' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' NOT EXISTS (SELECT * FROM RDB$CHECK_CONSTRAINTS CHK WHERE ' + {do not localize}
' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME) ' + {do not localize}
'ORDER BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, ' + {do not localize}
' TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME'; {do not localize}
TriggerByNameSQL =
'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$RELATIONS REL ON ' + {do not localize}
' TRG.RDB$RELATION_NAME = REL.RDB$RELATION_NAME ' + {do not localize}
'WHERE ' + {do not localize}
' TRG.RDB$TRIGGER_NAME = :TriggerName AND ' + {do not localize}
' (REL.RDB$SYSTEM_FLAG <> 1 OR REL.RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' NOT EXISTS (SELECT * FROM RDB$CHECK_CONSTRAINTS CHK WHERE ' + {do not localize}
' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME) ' + {do not localize}
'ORDER BY TRG.RDB$RELATION_NAME, TRG.RDB$TRIGGER_TYPE, ' + {do not localize}
' TRG.RDB$TRIGGER_SEQUENCE, TRG.RDB$TRIGGER_NAME'; {do not localize}
var
Header : Boolean;
TriggerName, RelationName, InActive: String;
qryTriggers : TIBSQL;
SList : TStrings;
begin
Header := true;
SList := TStringList.Create;
qryTriggers := CreateIBSQL;
try
if ObjectName = '' then {do not localize}
qryTriggers.SQL.Text := TriggerSQL
else
begin
if ExtractType = etTable then
begin
qryTriggers.SQL.Text := TriggerNameSQL;
qryTriggers.Params.ByName('TableName').AsTrimString := ObjectName; {do not localize}
end
else
begin
qryTriggers.SQL.Text := TriggerByNameSQL;
qryTriggers.Params.ByName('TriggerName').AsTrimString := ObjectName; {do not localize}
end;
end;
qryTriggers.ExecQuery;
while not qryTriggers.Eof do
begin
SList.Clear;
if Header then
begin
FMetaData.Add(Format('SET TERM %s %s%s', [Procterm, Term, NEWLINE])); {do not localize}
FMetaData.Add(Format('%s/* Triggers only will work for SQL triggers */%s', {do not localize}
[NEWLINE, NEWLINE]));
Header := false;
end;
TriggerName := qryTriggers.FieldByName('RDB$TRIGGER_NAME').AsTrimString; {do not localize}
RelationName := qryTriggers.FieldByName('RDB$RELATION_NAME').AsTrimString; {do not localize}
if qryTriggers.FieldByName('RDB$TRIGGER_INACTIVE').IsNull then {do not localize}
InActive := 'INACTIVE' {do not localize}
else
if qryTriggers.FieldByName('RDB$TRIGGER_INACTIVE').AsInteger = 1 then {do not localize}
InActive := 'INACTIVE' {do not localize}
else
InActive := 'ACTIVE'; {do not localize}
if qryTriggers.FieldByName('RDB$FLAGS').AsInteger <> 1 then {do not localize}
SList.Add('/* '); {do not localize}
SList.Add(Format('CREATE TRIGGER %s FOR %s %s%s %s POSITION %d', {do not localize}
[QuoteIdentifier(FDatabase.SQLDialect, TriggerName),
QuoteIdentifier(FDatabase.SQLDialect, RelationName),
NEWLINE, InActive,
TriggerTypes[qryTriggers.FieldByName('RDB$TRIGGER_TYPE').AsInteger], {do not localize}
qryTriggers.FieldByName('RDB$TRIGGER_SEQUENCE').AsInteger])); {do not localize}
if not qryTriggers.FieldByName('RDB$TRIGGER_SOURCE').IsNull then {do not localize}
SList.Text := SList.Text +
qryTriggers.FieldByName('RDB$TRIGGER_SOURCE').AsTrimString; {do not localize}
SList.Add(' ' + ProcTerm + NEWLINE);
if qryTriggers.FieldByName('RDB$FLAGS').AsInteger <> 1 then {do not localize}
SList.Add(' */'); {do not localize}
FMetaData.AddStrings(SList);
qryTriggers.Next;
end;
if not Header then
begin
FMetaData.Add('COMMIT WORK ' + ProcTerm); {do not localize}
FMetaData.Add('SET TERM ' + Term + ProcTerm); {do not localize}
end;
finally
qryTriggers.Free;
SList.Free;
end;
end;
{ ListCheck
Functional description
List check constraints for all objects to allow forward references }
procedure TIBExtract.ListCheck(ObjectName : String; ExtractType : TExtractType);
const
{ Query gets the check clauses for triggers stored for check constraints }
CheckSQL =
'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$CHECK_CONSTRAINTS CHK ON ' + {do not localize}
' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME ' + {do not localize}
'WHERE ' + {do not localize}
' TRG.RDB$TRIGGER_TYPE = 1 AND ' + {do not localize}
' EXISTS (SELECT RDB$CONSTRAINT_NAME FROM RDB$RELATION_CONSTRAINTS RELC WHERE ' + {do not localize}
' CHK.RDB$CONSTRAINT_NAME = RELC.RDB$CONSTRAINT_NAME) ' + {do not localize}
'ORDER BY CHK.RDB$CONSTRAINT_NAME'; {do not localize}
CheckNameSQL =
'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$CHECK_CONSTRAINTS CHK ON ' + {do not localize}
' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME ' + {do not localize}
'WHERE ' + {do not localize}
' TRG.RDB$RELATION_NAME = :TableName AND ' + {do not localize}
' TRG.RDB$TRIGGER_TYPE = 1 AND ' + {do not localize}
' EXISTS (SELECT RDB$CONSTRAINT_NAME FROM RDB$RELATION_CONSTRAINTS RELC WHERE ' + {do not localize}
' CHK.RDB$CONSTRAINT_NAME = RELC.RDB$CONSTRAINT_NAME) ' + {do not localize}
'ORDER BY CHK.RDB$CONSTRAINT_NAME'; {do not localize}
CheckByNameSQL =
'SELECT * FROM RDB$TRIGGERS TRG JOIN RDB$CHECK_CONSTRAINTS CHK ON ' + {do not localize}
' TRG.RDB$TRIGGER_NAME = CHK.RDB$TRIGGER_NAME ' + {do not localize}
'WHERE ' + {do not localize}
' TRG.RDB$TRIGGER_NAME = :TriggerName AND ' + {do not localize}
' TRG.RDB$TRIGGER_TYPE = 1 AND ' + {do not localize}
' EXISTS (SELECT RDB$CONSTRAINT_NAME FROM RDB$RELATION_CONSTRAINTS RELC WHERE ' + {do not localize}
' CHK.RDB$CONSTRAINT_NAME = RELC.RDB$CONSTRAINT_NAME) ' + {do not localize}
'ORDER BY CHK.RDB$CONSTRAINT_NAME'; {do not localize}
var
qryChecks : TIBSQL;
SList : TStrings;
RelationName : String;
begin
qryChecks := CreateIBSQL;
SList := TStringList.Create;
try
if ObjectName = '' then {do not localize}
qryChecks.SQL.Text := CheckSQL
else
if ExtractType = etTable then
begin
qryChecks.SQL.Text := CheckNameSQL;
qryChecks.Params.ByName('TableName').AsTrimString := ObjectName; {do not localize}
end
else
begin
qryChecks.SQL.Text := CheckByNameSQL;
qryChecks.Params.ByName('TriggerName').AsTrimString := ObjectName; {do not localize}
end;
qryChecks.ExecQuery;
while not qryChecks.Eof do
begin
SList.Clear;
RelationName := qryChecks.FieldByName('RDB$RELATION_NAME').AsTrimString; {do not localize}
SList.Add(Format('ALTER TABLE %s ADD', {do not localize}
[QuoteIdentifier(FDatabase.SQLDialect, RelationName)]));
if Pos('INTEG', qryChecks.FieldByName('RDB$CONSTRAINT_NAME').AsTrimString) <> 1 then {do not localize}
SList.Add(Format('%sCONSTRAINT %s ', [TAB, {do not localize}
QuoteIdentifier(FDatabase.SQLDialect, qryChecks.FieldByName('RDB$CONSTRAINT_NAME').AsTrimString)])); {do not localize}
if not qryChecks.FieldByName('RDB$TRIGGER_SOURCE').IsNull then {do not localize}
SList.Text := SList.Text + qryChecks.FieldByName('RDB$TRIGGER_SOURCE').AsTrimString; {do not localize}
SList.Strings[SList.Count - 1] := SList.Strings[SList.Count - 1] + (Term) + NEWLINE;
FMetaData.AddStrings(SList);
qryChecks.Next;
end;
finally
qryChecks.Free;
SList.Free;
end;
end;
{ ListCreateDb
Functional description
Print the create database command if requested. At least put
the page size in a comment with the extracted db name }
procedure TIBExtract.ListCreateDb(TargetDb : String);
const
CharInfoSQL =
'SELECT * FROM RDB$DATABASE DBP ' + {do not localize}
'WHERE NOT DBP.RDB$CHARACTER_SET_NAME IS NULL ' + {do not localize}
' AND DBP.RDB$CHARACTER_SET_NAME != '' '''; {do not localize}
FilesSQL =
'select * from RDB$FILES ' + {do not localize}
'order BY RDB$SHADOW_NUMBER, RDB$FILE_SEQUENCE'; {do not localize}
LogsSQL =
'SELECT * FROM RDB$LOG_FILES ' + {do not localize}
'ORDER BY RDB$FILE_FLAGS, RDB$FILE_SEQUENCE'; {do not localize}
var
NoDb, First, FirstFile, HasWal, SetUsed : Boolean;
Buffer : String;
qryDB : TIBSQL;
FileFlags, FileLength, FileSequence, FileStart : Integer;
function GetLongDatabaseInfo(DatabaseInfoCommand: Integer): LongInt;
var
local_buffer: array[0..IBLocalBufferLength - 1] of Char;
length: Integer;
_DatabaseInfoCommand: Char;
begin
_DatabaseInfoCommand := Char(DatabaseInfoCommand);
FDatabaseInfo.Call(isc_database_info(StatusVector, @FDatabase.Handle, 1, @_DatabaseInfoCommand,
IBLocalBufferLength, local_buffer), True);
length := isc_vax_integer(@local_buffer[1], 2);
result := isc_vax_integer(@local_buffer[3], length);
end;
begin
NoDb := FALSE;
First := TRUE;
FirstFile := TRUE;
HasWal := FALSE;
SetUsed := FALSE;
Buffer := ''; {do not localize}
if TargetDb = '' then {do not localize}
begin
Buffer := '/* '; {do not localize}
TargetDb := FDatabase.DatabaseName;
NoDb := true;
end;
Buffer := Buffer + 'CREATE DATABASE ' + QuotedStr(TargetDb) + ' PAGE_SIZE ' + {do not localize}
IntToStr(FDatabaseInfo.PageSize) + NEWLINE;
FMetaData.Add(Buffer);
Buffer := '';
qryDB := CreateIBSQL;
try
qryDB.SQL.Text := CharInfoSQL;
qryDB.ExecQuery;
Buffer := Format(' DEFAULT CHARACTER SET %s', {do not localize}
[qryDB.FieldByName('RDB$CHARACTER_SET_NAME').AsTrimString]); {do not localize}
if NoDB then
Buffer := Buffer + ' */' {do not localize}
else
Buffer := Buffer + Term;
FMetaData.Add(Buffer);
qryDB.Close;
{List secondary files and shadows as
alter db and create shadow in comment}
qryDB.SQL.Text := FilesSQL;
qryDB.ExecQuery;
while not qryDB.Eof do
begin
if First then
begin
FMetaData.Add(NEWLINE + '/* Add secondary files in comments '); {do not localize}
First := false;
end; //end_if
if qryDB.FieldByName('RDB$FILE_FLAGS').IsNull then {do not localize}
FileFlags := 0
else
FileFlags := qryDB.FieldByName('RDB$FILE_FLAGS').AsInteger; {do not localize}
if qryDB.FieldByName('RDB$FILE_LENGTH').IsNull then {do not localize}
FileLength := 0
else
FileLength := qryDB.FieldByName('RDB$FILE_LENGTH').AsInteger; {do not localize}
if qryDB.FieldByName('RDB$FILE_SEQUENCE').IsNull then {do not localize}
FileSequence := 0
else
FileSequence := qryDB.FieldByName('RDB$FILE_SEQUENCE').AsInteger; {do not localize}
if qryDB.FieldByName('RDB$FILE_START').IsNull then {do not localize}
FileStart := 0
else
FileStart := qryDB.FieldByName('RDB$FILE_START').AsInteger; {do not localize}
{ Pure secondary files }
if FileFlags = 0 then
begin
Buffer := Format('%sALTER DATABASE ADD FILE ''%s''', {do not localize}
[NEWLINE, qryDB.FieldByName('RDB$FILE_NAME').AsTrimString]); {do not localize}
if FileStart <> 0 then
Buffer := Buffer + Format(' STARTING %d', [FileStart]); {do not localize}
if FileLength <> 0 then
Buffer := Buffer + Format(' LENGTH %d', [FileLength]); {do not localize}
FMetaData.Add(Buffer);
end; //end_if
if (FileFlags and FILE_cache) <> 0 then
FMetaData.Add(Format('%sALTER DATABASE ADD CACHE ''%s'' LENGTH %d', {do not localize}
[NEWLINE, qryDB.FieldByName('RDB$FILE_NAME').AsTrimString, FileLength])); {do not localize}
Buffer := '';
if (FileFlags and FILE_shadow) <> 0 then
begin
if FileSequence <> 0 then
Buffer := Format('%sFILE ''%s''', {do not localize}
[TAB, qryDB.FieldByName('RDB$FILE_NAME').AsTrimString]) {do not localize}
else
begin
Buffer := Format('%sCREATE SHADOW %d ''%s'' ', {do not localize}
[NEWLINE, qryDB.FieldByName('RDB$SHADOW_NUMBER').AsInteger, {do not localize}
qryDB.FieldByName('RDB$FILE_NAME').AsTrimString]); {do not localize}
if (FileFlags and FILE_inactive) <> 0 then
Buffer := Buffer + 'INACTIVE '; {do not localize}
if (FileFlags and FILE_manual) <> 0 then
Buffer := Buffer + 'MANUAL ' {do not localize}
else
Buffer := Buffer + 'AUTO '; {do not localize}
if (FileFlags and FILE_conditional) <> 0 then
Buffer := Buffer + 'CONDITIONAL '; {do not localize}
end; //end_else
if FileLength <> 0 then
Buffer := Buffer + Format('LENGTH %d ', [FileLength]); {do not localize}
if FileStart <> 0 then
Buffer := Buffer + Format('STARTING %d ', [FileStart]); {do not localize}
FMetaData.Add(Buffer);
end; //end_if
qryDB.Next;
end;
qryDB.Close;
qryDB.SQL.Text := LogsSQL;
qryDB.ExecQuery;
while not qryDB.Eof do
begin
if qryDB.FieldByName('RDB$FILE_FLAGS').IsNull then {do not localize}
FileFlags := 0
else
FileFlags := qryDB.FieldByName('RDB$FILE_FLAGS').AsInteger; {do not localize}
if qryDB.FieldByName('RDB$FILE_LENGTH').IsNull then {do not localize}
FileLength := 0
else
FileLength := qryDB.FieldByName('RDB$FILE_LENGTH').AsInteger; {do not localize}
Buffer := '';
HasWal := true;
if First then
begin
if NoDB then
Buffer := '/* '; {do not localize}
Buffer := Buffer + NEWLINE + 'ALTER DATABASE ADD '; {do not localize}
First := false;
end; //end_if
if FirstFile then
Buffer := Buffer + 'LOGFILE '; {do not localize}
{ Overflow files also have the serial bit set }
if (FileFlags and LOG_default) = 0 then
begin
if (FileFlags and LOG_overflow) <> 0 then
Buffer := Buffer + Format(')%s OVERFLOW ''%s''', {do not localize}
[NEWLINE, qryDB.FieldByName('RDB$FILE_NAME').AsTrimString]) {do not localize}
else
if (FileFlags and LOG_serial) <> 0 then
Buffer := Buffer + Format('%s BASE_NAME ''%s''', {do not localize}
[NEWLINE, qryDB.FieldByName('RDB$FILE_NAME').AsTrimString]) {do not localize}
{ Since we are fetching order by FILE_FLAGS, the LOG_0verflow will
be last. It will only appear if there were named round robin,
so we must close the parens first }
{ We have round robin and overflow file specifications }
else
begin
if FirstFile then
Buffer := Buffer + '(' {do not localize}
else
Buffer := Buffer + Format(',%s ', [NEWLINE]); {do not localize}
FirstFile := false;
Buffer := Buffer + Format('''%s''', [qryDB.FieldByName('RDB$FILE_NAME').AsTrimString]); {do not localize}
end; //end_else
end;
{ Any file can have a length }
if FileLength <> 0 then
Buffer := Buffer + Format(' SIZE %d ', [FileLength]); {do not localize}
FMetaData.Add(Buffer);
qryDB.Next;
end;
qryDB.Close;
Buffer := '';
if HasWal then
begin
Buffer := Buffer + PrintSet(SetUsed);
Buffer := Buffer + Format('NUM_LOG_BUFFERS = %d', {do not localize}
[GetLongDatabaseInfo(isc_info_num_wal_buffers)]);
Buffer := Buffer + PrintSet(SetUsed);
Buffer := Buffer + Format('LOG_BUFFER_SIZE = %d', {do not localize}
[GetLongDatabaseInfo(isc_info_wal_buffer_size)]);
Buffer := Buffer + PrintSet(SetUsed);
Buffer := Buffer + Format('GROUP_COMMIT_WAIT_TIME = %d', {do not localize}
[GetLongDatabaseInfo(isc_info_wal_grpc_wait_usecs)]);
Buffer := Buffer + PrintSet(SetUsed);
Buffer := Buffer + Format('CHECK_POINT_LENGTH = %d', {do not localize}
[GetLongDatabaseInfo(isc_info_wal_ckpt_length)]);
FMetaData.Add(Buffer);
end;
if not First then
begin
if NoDB then
FMetaData.Add(Format('%s */%s', [NEWLINE, NEWLINE])) {do not localize}
else
FMetaData.Add(Format('%s%s%s', [Term, NEWLINE, NEWLINE])); {do not localize}
end;
finally
qryDB.Free;
end;
end;
{ ListDomainTable
Functional description
List domains as identified by fields with any constraints on them
for the named table
Parameters: table_name == only extract domains for this table }
procedure TIBExtract.ListDomains(ObjectName: String; ExtractType : TExtractType);
const
DomainSQL =
'SELECT distinct fld.* FROM RDB$FIELDS FLD JOIN RDB$RELATION_FIELDS RFR ON ' + {do not localize}
' RFR.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME ' + {do not localize}
'WHERE RFR.RDB$RELATION_NAME = :TABLE_NAME ' + {do not localize}
'ORDER BY FLD.RDB$FIELD_NAME'; {do not localize}
DomainByNameSQL =
'SELECT * FROM RDB$FIELDS FLD ' + {do not localize}
'WHERE FLD.RDB$FIELD_NAME = :DomainName ' + {do not localize}
'ORDER BY FLD.RDB$FIELD_NAME'; {do not localize}
AllDomainSQL =
'select * from RDB$FIELDS ' + {do not localize}
'where RDB$SYSTEM_FLAG <> 1 ' + {do not localize}
'order BY RDB$FIELD_NAME'; {do not localize}
var
First : Boolean;
qryDomains : TIBSQL;
FieldName, Line : String;
function FormatDomainStr : String;
var
i, SubType : Integer;
PrecisionKnown : Boolean;
begin
Result := ''; {do not localize}
for i := Low(ColumnTypes) to High(ColumnTypes) do
if qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = ColumnTypes[i].SQLType then {do not localize}
begin
PrecisionKnown := FALSE;
if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
begin
if qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_short, blr_long, blr_int64] then {do not localize}
begin
{ We are ODS >= 10 and could be any Dialect }
if (FDatabaseInfo.DBSQLDialect >= 3) and
(not qryDomains.FieldByName('RDB$FIELD_PRECISION').IsNull) and {do not localize}
(qryDomains.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger > 0) and {do not localize}
(qryDomains.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger <= MAX_INTSUBTYPES) then {do not localize}
begin
Result := Result + Format('%s(%d, %d)', [ {do not localize}
IntegralSubtypes [qryDomains.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger], {do not localize}
qryDomains.FieldByName('RDB$FIELD_PRECISION').AsInteger, {do not localize}
-1 * qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger]); {do not localize}
PrecisionKnown := true;
end;
end;
end;
if PrecisionKnown = false then
begin
{ Take a stab at numerics and decimals }
if (qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_short) and {do not localize}
(qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then {do not localize}
Result := Result + Format('NUMERIC(4, %d)', {do not localize}
[-qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger] ) {do not localize}
else
if (qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_long) and {do not localize}
(qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then {do not localize}
Result := Result + Format('NUMERIC(9, %d)', {do not localize}
[-qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger] ) {do not localize}
else
if (qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_double) and {do not localize}
(qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then {do not localize}
Result := Result + Format('NUMERIC(15, %d)', {do not localize}
[-qryDomains.FieldByName('RDB$FIELD_SCALE').AsInteger] ) {do not localize}
else
Result := Result + ColumnTypes[i].TypeName;
end;
break;
end;
if qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_blob then {do not localize}
begin
subtype := qryDomains.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger; {do not localize}
Result := Result + ' SUB_TYPE '; {do not localize}
if (subtype > 0) and (subtype <= MAXSUBTYPES) then
Result := Result + SubTypes[subtype]
else
Result := Result + Format('%d', [subtype]); {do not localize}
Result := Result + Format(' SEGMENT SIZE %d', [qryDomains.FieldByName('RDB$SEGMENT_LENGTH').AsInteger]); {do not localize}
end //end_if
else
if qryDomains.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_text, blr_varying] then {do not localize}
Result := Result + Format('(%d)', [GetFieldLength(qryDomains)]); {do not localize}
{ since the character set is part of the field type, display that
information now. }
if not qryDomains.FieldByName('RDB$CHARACTER_SET_ID').IsNull then {do not localize}
Result := Result + GetCharacterSets(qryDomains.FieldByName('RDB$CHARACTER_SET_ID').AsInteger, {do not localize}
0, FALSE);
if not qryDomains.FieldByName('RDB$DIMENSIONS').IsNull then {do not localize}
Result := Result + GetArrayField(FieldName);
if not qryDomains.FieldByName('RDB$DEFAULT_SOURCE').IsNull then {do not localize}
Result := Result + Format('%s%s %s', [NEWLINE, TAB, {do not localize}
qryDomains.FieldByName('RDB$DEFAULT_SOURCE').AsTrimString]); {do not localize}
if not qryDomains.FieldByName('RDB$VALIDATION_SOURCE').IsNull then {do not localize}
if Pos('CHECK', AnsiUpperCase(qryDomains.FieldByName('RDB$VALIDATION_SOURCE').AsTrimString)) = 1 then {do not localize}
Result := Result + Format('%s%s %s', [NEWLINE, TAB, {do not localize}
qryDomains.FieldByName('RDB$VALIDATION_SOURCE').AsTrimString]) {do not localize}
else
Result := Result + Format('%s%s /* %s */', [NEWLINE, TAB, {do not localize}
qryDomains.FieldByName('RDB$VALIDATION_SOURCE').AsTrimString]); {do not localize}
if qryDomains.FieldByName('RDB$NULL_FLAG').AsInteger = 1 then {do not localize}
Result := Result + ' NOT NULL'; {do not localize}
{ Show the collation order if one has been specified. If the collation
order is the default for the character set being used, then no collation
order will be shown ( because it isn't needed ).
If the collation id is 0, then the default for the character set is
being used so there is no need to retrieve the collation information.}
if (not qryDomains.FieldByName('RDB$COLLATION_ID').IsNull) and {do not localize}
(qryDomains.FieldByName('RDB$COLLATION_ID').AsInteger <> 0) then {do not localize}
Result := Result + GetCharacterSets(qryDomains.FieldByName('RDB$CHARACTER_SET_ID').AsInteger, {do not localize}
qryDomains.FieldByName('RDB$COLLATION_ID').AsInteger, true); {do not localize}
end;
begin
First := true;
qryDomains := CreateIBSQL;
try
if ObjectName <> '' then {do not localize}
begin
if ExtractType = etTable then
begin
qryDomains.SQL.Text := DomainSQL;
qryDomains.Params.ByName('table_name').AsTrimString := ObjectName; {do not localize}
end
else
begin
qryDomains.SQL.Text := DomainByNameSQL;
qryDomains.Params.ByName('DomainName').AsTrimString := ObjectName; {do not localize}
end;
end
else
qryDomains.SQL.Text := AllDomainSQL;
qryDomains.ExecQuery;
while not qryDomains.Eof do
begin
FieldName := qryDomains.FieldByName('RDB$FIELD_NAME').AsTrimString; {do not localize}
{ Skip over artifical domains }
if (Pos('RDB$',FieldName) = 1) and {do not localize}
(FieldName[5] in ['0'..'9']) and {do not localize}
(qryDomains.FieldByName('RDB$SYSTEM_FLAG').AsInteger <> 1) then {do not localize}
begin
qryDomains.Next;
continue;
end;
if First then
begin
FMetaData.Add('/* Domain definitions */'); {do not localize}
First := false;
end;
Line := Format('CREATE DOMAIN %s AS ', [QuoteIdentifier(FDatabase.SQLDialect, FieldName)]); {do not localize}
Line := Line + FormatDomainStr + Term;
FMetaData.Add(Line);
qryDomains.Next;
end;
finally
qryDomains.Free;
end;
end;
{ ListException
Functional description
List all exceptions defined in the database
Parameters: none }
procedure TIBExtract.ListException(ExceptionName : String = '');
const
ExceptionSQL =
'select * from RDB$EXCEPTIONS ' + {do not localize}
'ORDER BY RDB$EXCEPTION_NAME'; {do not localize}
ExceptionNameSQL =
'select * from RDB$EXCEPTIONS ' + {do not localize}
'WHERE RDB$EXCEPTION_NAME = :ExceptionName ' + {do not localize}
'ORDER BY RDB$EXCEPTION_NAME'; {do not localize}
var
First : Boolean;
qryException : TIBSQL;
begin
First := true;
qryException := CreateIBSQL;
try
if ExceptionName = '' then {do not localize}
qryException.SQL.Text := ExceptionSQL
else
begin
qryException.SQL.Text := ExceptionNameSQL;
qryException.Params.ByName('ExceptionName').AsTrimString := ExceptionName; {do not localize}
end;
qryException.ExecQuery;
while not qryException.Eof do
begin
if First then
begin
FMetaData.Add(''); {do not localize}
FMetaData.Add('/* Exceptions */'); {do not localize}
FMetaData.Add(''); {do not localize}
First := false;
end; //end_if
FMetaData.Add(Format('CREATE EXCEPTION %s %s%s', {do not localize}
[QuoteIdentifier(FDatabase.SQLDialect, qryException.FieldByName('RDB$EXCEPTION_NAME').AsTrimString), {do not localize}
QuotedStr(qryException.FieldByName('RDB$MESSAGE').AsTrimString), Term])); {do not localize}
qryException.Next;
end;
finally
qryException.Free;
end;
end;
{ ListFilters
Functional description
List all blob filters
Parameters: none
Results in
DECLARE FILTER <fname> INPUT_TYPE <blob_sub_type> OUTPUT_TYPE <blob_subtype>
ENTRY_POINT <string> MODULE_NAME <string> }
procedure TIBExtract.ListFilters(FilterName : String = '');
const
FiltersSQL =
'SELECT * FROM RDB$FILTERS ' + {do not localize}
'ORDER BY RDB$FUNCTION_NAME'; {do not localize}
FilterNameSQL =
'SELECT * FROM RDB$FILTERS ' + {do not localize}
'WHERE RDB$FUNCTION_NAME = :FunctionName ' + {do not localize}
'ORDER BY RDB$FUNCTION_NAME'; {do not localize}
var
First : Boolean;
qryFilters : TIBSQL;
begin
First := true;
qryFilters := CreateIBSQL;
try
if FilterName = '' then {do not localize}
qryFilters.SQL.Text := FiltersSQL
else
begin
qryFilters.SQL.Text := FilterNameSQL;
qryFilters.Params.ByName('FunctionName').AsTrimString := FilterName; {do not localize}
end;
qryFilters.ExecQuery;
while not qryFilters.Eof do
begin
if First then
begin
FMetaData.Add(''); {do not localize}
FMetaData.Add('/* BLOB Filter declarations */'); {do not localize}
FMetaData.Add(''); {do not localize}
First := false;
end; //end_if
FMetaData.Add(Format('DECLARE FILTER %s INPUT_TYPE %d OUTPUT_TYPE %d', {do not localize}
[qryFilters.FieldByName('RDB$FUNCTION_NAME').AsTrimString, {do not localize}
qryFilters.FieldByName('RDB$INPUT_SUB_TYPE').AsInteger, {do not localize}
qryFilters.FieldByName('RDB$OUTPUT_SUB_TYPE').AsInteger])); {do not localize}
FMetaData.Add(Format('%sENTRY_POINT ''%s'' MODULE_NAME ''%s''%s%', {do not localize}
[TAB, qryFilters.FieldByName('RDB$ENTRYPOINT').AsTrimString, {do not localize}
qryFilters.FieldByName('RDB$MODULE_NAME').AsTrimString, Term])); {do not localize}
FMetaData.Add(''); {do not localize}
qryFilters.Next;
end;
finally
qryFilters.Free;
end;
end;
{ ListForeign
Functional description
List all foreign key constraints and alter the tables }
procedure TIBExtract.ListForeign(ObjectName : String; ExtractType : TExtractType);
const
{ Static queries for obtaining foreign constraints, where RELC1 is the
foreign key constraints, RELC2 is the primary key lookup and REFC
is the join table }
ForeignSQL =
'SELECT REFC.RDB$UPDATE_RULE REFC_UPDATE_RULE, REFC.RDB$DELETE_RULE REFC_DELETE_RULE, ' + {do not localize}
' RELC1.RDB$RELATION_NAME RELC1_RELATION_NAME, RELC2.RDB$RELATION_NAME RELC2_RELATION_NAME, ' + {do not localize}
' RELC1.RDB$INDEX_NAME RELC1_INDEX_NAME, RELC1.RDB$CONSTRAINT_NAME RELC1_CONSTRAINT_NAME, ' + {do not localize}
' RELC2.RDB$INDEX_NAME RELC2_INDEX_NAME ' + {do not localize}
'FROM RDB$REF_CONSTRAINTS REFC, RDB$RELATION_CONSTRAINTS RELC1, ' + {do not localize}
' RDB$RELATION_CONSTRAINTS RELC2 ' + {do not localize}
'WHERE ' + {do not localize}
' RELC1.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' AND ' + {do not localize}
' REFC.RDB$CONST_NAME_UQ = RELC2.RDB$CONSTRAINT_NAME AND ' + {do not localize}
' REFC.RDB$CONSTRAINT_NAME = RELC1.RDB$CONSTRAINT_NAME AND ' + {do not localize}
' (RELC2.RDB$CONSTRAINT_TYPE = ''UNIQUE'' OR ' + {do not localize}
' RELC2.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'') ' + {do not localize}
'ORDER BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME'; {do not localize}
ForeignNameSQL =
'SELECT REFC.RDB$UPDATE_RULE REFC_UPDATE_RULE, REFC.RDB$DELETE_RULE REFC_DELETE_RULE, ' + {do not localize}
' RELC1.RDB$RELATION_NAME RELC1_RELATION_NAME, RELC2.RDB$RELATION_NAME RELC2_RELATION_NAME, ' + {do not localize}
' RELC1.RDB$INDEX_NAME RELC1_INDEX_NAME, RELC1.RDB$CONSTRAINT_NAME RELC1_CONSTRAINT_NAME, ' + {do not localize}
' RELC2.RDB$INDEX_NAME RELC2_INDEX_NAME ' + {do not localize}
'FROM RDB$REF_CONSTRAINTS REFC, RDB$RELATION_CONSTRAINTS RELC1, ' + {do not localize}
' RDB$RELATION_CONSTRAINTS RELC2 ' + {do not localize}
'WHERE ' + {do not localize}
' RELC1.RDB$RELATION_NAME = :TableName AND ' + {do not localize}
' RELC1.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' AND ' + {do not localize}
' REFC.RDB$CONST_NAME_UQ = RELC2.RDB$CONSTRAINT_NAME AND ' + {do not localize}
' REFC.RDB$CONSTRAINT_NAME = RELC1.RDB$CONSTRAINT_NAME AND ' + {do not localize}
' (RELC2.RDB$CONSTRAINT_TYPE = ''UNIQUE'' OR ' + {do not localize}
' RELC2.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'') ' + {do not localize}
'ORDER BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME'; {do not localize}
ForeignByNameSQL =
'SELECT REFC.RDB$UPDATE_RULE REFC_UPDATE_RULE, REFC.RDB$DELETE_RULE REFC_DELETE_RULE, ' + {do not localize}
' RELC1.RDB$RELATION_NAME RELC1_RELATION_NAME, RELC2.RDB$RELATION_NAME RELC2_RELATION_NAME, ' + {do not localize}
' RELC1.RDB$INDEX_NAME RELC1_INDEX_NAME, RELC1.RDB$CONSTRAINT_NAME RELC1_CONSTRAINT_NAME, ' + {do not localize}
' RELC2.RDB$INDEX_NAME RELC2_INDEX_NAME ' + {do not localize}
'FROM RDB$REF_CONSTRAINTS REFC, RDB$RELATION_CONSTRAINTS RELC1, ' + {do not localize}
' RDB$RELATION_CONSTRAINTS RELC2 ' + {do not localize}
'WHERE ' + {do not localize}
' RELC1.RDB$CONSTRAINT_NAME = :ConstraintName AND ' + {do not localize}
' RELC1.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' AND ' + {do not localize}
' REFC.RDB$CONST_NAME_UQ = RELC2.RDB$CONSTRAINT_NAME AND ' + {do not localize}
' REFC.RDB$CONSTRAINT_NAME = RELC1.RDB$CONSTRAINT_NAME AND ' + {do not localize}
' (RELC2.RDB$CONSTRAINT_TYPE = ''UNIQUE'' OR ' + {do not localize}
' RELC2.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'') ' + {do not localize}
'ORDER BY RELC1.RDB$RELATION_NAME, RELC1.RDB$CONSTRAINT_NAME'; {do not localize}
var
qryForeign : TIBSQL;
Line : String;
begin
qryForeign := CreateIBSQL;
try
if ObjectName = '' then {do not localize}
qryForeign.SQL.Text := ForeignSQL
else
begin
if ExtractType = etTable then
begin
qryForeign.SQL.Text := ForeignNameSQL;
qryForeign.Params.ByName('TableName').AsTrimString := ObjectName; {do not localize}
end
else
begin
qryForeign.SQL.Text := ForeignByNameSQL;
qryForeign.Params.ByName('ConstraintName').AsTrimString := ObjectName; {do not localize}
end;
end;
qryForeign.ExecQuery;
while not qryForeign.Eof do
begin
Line := Format('ALTER TABLE %s ADD ', [QuoteIdentifier(FDatabase.SQLDialect, {do not localize}
qryForeign.FieldByName('RELC1_RELATION_NAME').AsTrimString)]); {do not localize}
{ If the name of the constraint is not INTEG..., print it.
INTEG... are internally generated names. }
if (not qryForeign.FieldByName('RELC1_CONSTRAINT_NAME').IsNull) and {do not localize}
( Pos('INTEG', qryForeign.FieldByName('RELC1_CONSTRAINT_NAME').AsTrimString) <> 1) then {do not localize}
Line := Line + Format('CONSTRAINT %s ', [QuoteIdentifier(FDatabase.SQLDialect, {do not localize}
Trim(qryForeign.FieldByName('RELC1_CONSTRAINT_NAME').AsTrimString))]); {do not localize}
Line := Line + Format('FOREIGN KEY (%s) REFERENCES %s ', [ {do not localize}
GetIndexSegments(qryForeign.FieldByName('RELC1_INDEX_NAME').AsTrimString), {do not localize}
Trim(qryForeign.FieldByName('RELC2_RELATION_NAME').AsTrimString)]); {do not localize}
Line := Line + Format('(%s)', {do not localize}
[GetIndexSegments(qryForeign.FieldByName('RELC2_INDEX_NAME').AsTrimString)]); {do not localize}
{ Add the referential actions, if any }
if (not qryForeign.FieldByName('REFC_UPDATE_RULE').IsNull) and {do not localize}
(Trim(qryForeign.FieldByName('REFC_UPDATE_RULE').AsTrimString) <> 'RESTRICT') then {do not localize}
Line := Line + Format(' ON UPDATE %s', {do not localize}
[Trim(qryForeign.FieldByName('REFC_UPDATE_RULE').AsTrimString)]); {do not localize}
if (not qryForeign.FieldByName('REFC_DELETE_RULE').IsNull) and {do not localize}
(Trim(qryForeign.FieldByName('REFC_DELETE_RULE').AsTrimString) <> 'RESTRICT') then {do not localize}
Line := Line + Format(' ON DELETE %s', {do not localize}
[Trim(qryForeign.FieldByName('REFC_DELETE_RULE').AsTrimString)]); {do not localize}
Line := Line + Term;
FMetaData.Add(Line);
qryForeign.Next;
end;
finally
qryForeign.Free;
end;
end;
{ ListFunctions
Functional description
List all external functions
Parameters: none
Results in
DECLARE EXTERNAL FUNCTION function_name
CHAR [256] , INTEGER, ....
RETURNS INTEGER BY VALUE
ENTRY_POINT entrypoint MODULE_NAME module; }
procedure TIBExtract.ListFunctions(FunctionName : String = '');
const
FunctionSQL =
'SELECT * FROM RDB$FUNCTIONS ' + {do not localize}
'ORDER BY RDB$FUNCTION_NAME'; {do not localize}
FunctionNameSQL =
'SELECT * FROM RDB$FUNCTIONS ' + {do not localize}
'WHERE RDB$FUNCTION_NAME = :FunctionName ' + {do not localize}
'ORDER BY RDB$FUNCTION_NAME'; {do not localize}
FunctionArgsSQL =
'SELECT * FROM RDB$FUNCTION_ARGUMENTS ' + {do not localize}
'WHERE ' + {do not localize}
' :FUNCTION_NAME = RDB$FUNCTION_NAME ' + {do not localize}
'ORDER BY RDB$ARGUMENT_POSITION'; {do not localize}
FuncArgsPosSQL =
'SELECT * FROM RDB$FUNCTION_ARGUMENTS ' + {do not localize}
'WHERE ' + {do not localize}
' RDB$FUNCTION_NAME = :RDB$FUNCTION_NAME AND ' + {do not localize}
' RDB$ARGUMENT_POSITION = :RDB$ARGUMENT_POSITION'; {do not localize}
CharSetSQL =
'SELECT * FROM RDB$CHARACTER_SETS ' + {do not localize}
'WHERE ' + {do not localize}
' RDB$CHARACTER_SET_ID = :CHARACTER_SET_ID'; {do not localize}
var
qryFunctions, qryFuncArgs, qryCharSets, qryFuncPos : TIBSQL;
First, FirstArg, DidCharset, PrecisionKnown : Boolean;
ReturnBuffer, TypeBuffer, Line : String;
i, FieldType : Integer;
begin
First := true;
qryFunctions := CreateIBSQL;
qryFuncArgs := CreateIBSQL;
qryFuncPos := CreateIBSQL;
qryCharSets := CreateIBSQL;
try
if FunctionName = '' then {do not localize}
qryFunctions.SQL.Text := FunctionSQL
else
begin
qryFunctions.SQL.Text := FunctionNameSQL;
qryFunctions.Params.ByName('FunctionName').AsTrimString := FunctionName; {do not localize}
end;
qryFuncArgs.SQL.Text := FunctionArgsSQL;
qryFuncPos.SQL.Text := FuncArgsPosSQL;
qryCharSets.SQL.Text := CharSetSQL;
qryFunctions.ExecQuery;
while not qryFunctions.Eof do
begin
if First then
begin
FMEtaData.Add(Format('%s/* External Function declarations */%s', {do not localize}
[NEWLINE, NEWLINE]));
First := false;
end; //end_if
{ Start new function declaration }
FMetaData.Add(Format('DECLARE EXTERNAL FUNCTION %s', {do not localize}
[qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsTrimString])); {do not localize}
Line := ''; {do not localize}
FirstArg := true;
qryFuncArgs.Params.ByName('FUNCTION_NAME').AsTrimString := {do not localize}
qryFunctions.FieldByName('RDB$FUNCTION_NAME').AsTrimString; {do not localize}
qryFuncArgs.ExecQuery;
while not qryFuncArgs.Eof do
begin
{ Find parameter type }
i := 0;
FieldType := qryFuncArgs.FieldByName('RDB$FIELD_TYPE').AsInteger; {do not localize}
while FieldType <> ColumnTypes[i].SQLType do
Inc(i);
{ Print length where appropriate }
if FieldType in [ blr_text, blr_varying, blr_cstring] then
begin
DidCharset := false;
qryCharSets.Params.ByName('CHARACTER_SET_ID').AsInteger := {do not localize}
qryFuncArgs.FieldByName('RDB$CHARACTER_SET_ID').AsInteger; {do not localize}
qryCharSets.ExecQuery;
while not qryCharSets.Eof do
begin
DidCharset := true;
TypeBuffer := Format('%s(%d) CHARACTER SET %s', {do not localize}
[ColumnTypes[i].TypeName,
qryFuncArgs.FieldByName('RDB$FIELD_LENGTH').AsInteger div {do not localize}
Max(1,qryCharSets.FieldByName('RDB$BYTES_PER_CHARACTER').AsInteger), {do not localize}
qryCharSets.FieldByName('RDB$CHARACTER_SET_NAME').AsTrimString]); {do not localize}
qryCharSets.Next;
end;
qryCharSets.Close;
if not DidCharset then
TypeBuffer := Format('%s(%d)', [ColumnTypes[i].TypeName, {do not localize}
qryFuncArgs.FieldByName('RDB$FIELD_LENGTH').AsInteger]); {do not localize}
end //end_if
else
begin
PrecisionKnown := false;
if (FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10) and
(FieldType in [blr_short, blr_long, blr_int64]) then
begin
qryFuncPos.Params.ByName('RDB$FUNCTION_NAME').AsTrimString := {do not localize}
qryFuncArgs.FieldByName('RDB$FUNCTION_NAME').AsTrimString; {do not localize}
qryFuncPos.Params.ByName('RDB$ARGUMENT_POSITION').AsInteger := {do not localize}
qryFuncArgs.FieldByName('RDB$ARGUMENT_POSITION').AsInteger; {do not localize}
qryFuncPos.ExecQuery;
while not qryFuncPos.Eof do
begin
{ We are ODS >= 10 and could be any Dialect }
if not qryFuncPos.FieldByName('RDB$FIELD_PRECISION').IsNull then {do not localize}
begin
{ We are Dialect >=3 since FIELD_PRECISION is non-NULL }
if (qryFuncPos.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger > 0) and {do not localize}
(qryFuncPos.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger <= MAX_INTSUBTYPES) then {do not localize}
begin
TypeBuffer := Format('%s(%d, %d)', {do not localize}
[IntegralSubtypes[qryFuncPos.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger], {do not localize}
qryFuncPos.FieldByName('RDB$FIELD_PRECISION').AsInteger, {do not localize}
-qryFuncPos.FieldByName('RDB$FIELD_SCALE').AsInteger] ); {do not localize}
PrecisionKnown := true;
end; //end_if
end; { if field_precision is not null }
qryFuncPos.Next;
end;
qryFuncPos.Close;
end; { if major_ods >= ods_version10 && }
if not PrecisionKnown then
begin
{ Take a stab at numerics and decimals }
if (FieldType = blr_short) and
(qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then {do not localize}
TypeBuffer := Format('NUMERIC(4, %d)', {do not localize}
[-qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger]) {do not localize}
else
if (FieldType = blr_long) and
(qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then {do not localize}
TypeBuffer := Format('NUMERIC(9, %d)', {do not localize}
[-qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger]) {do not localize}
else
if (FieldType = blr_double) and
(qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then {do not localize}
TypeBuffer := Format('NUMERIC(15, %d)', {do not localize}
[-qryFuncArgs.FieldByName('RDB$FIELD_SCALE').AsInteger]) {do not localize}
else
TypeBuffer := ColumnTypes[i].TypeName;
end; { if not PrecisionKnown }
end; { if FCHAR or VARCHAR or CSTRING ... else }
if qryFunctions.FieldByName('RDB$RETURN_ARGUMENT').AsInteger = {do not localize}
qryFuncArgs.FieldByName('RDB$ARGUMENT_POSITION').AsInteger then {do not localize}
begin
ReturnBuffer := 'RETURNS ' + TypeBuffer; {do not localize}
if qryFuncArgs.FieldByName('RDB$MECHANISM').AsInteger = 0 then {do not localize}
ReturnBuffer := ReturnBuffer + ' BY VALUE '; {do not localize}
if qryFuncArgs.FieldByName('RDB$MECHANISM').AsInteger < 0 then {do not localize}
ReturnBuffer := ReturnBuffer + ' FREE_IT'; {do not localize}
end
else
begin
{ First arg needs no comma }
if FirstArg then
begin
Line := Line + TypeBuffer;
FirstArg := false;
end
else
Line := Line + ', ' + TypeBuffer;
end; //end_else
qryFuncArgs.Next;
end;
qryFuncArgs.Close;
FMetaData.Add(Line);
FMetaData.Add(ReturnBuffer);
FMetaData.Add(Format('ENTRY_POINT ''%s'' MODULE_NAME ''%s''%s%s%s', {do not localize}
[qryFunctions.FieldByName('RDB$ENTRYPOINT').AsTrimString, {do not localize}
qryFunctions.FieldByName('RDB$MODULE_NAME').AsTrimString, {do not localize}
Term, NEWLINE, NEWLINE]));
qryFunctions.Next;
end;
finally
qryFunctions.Free;
qryFuncArgs.Free;
qryCharSets.Free;
qryFuncPos.Free;
end;
end;
{ ListGenerators
Functional description
Re create all non-system generators }
procedure TIBExtract.ListGenerators(GeneratorName : String = ''); {do not localize}
const
GeneratorSQL =
'SELECT RDB$GENERATOR_NAME ' + {do not localize}
'FROM RDB$GENERATORS ' + {do not localize}
'WHERE ' + {do not localize}
' (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG <> 1) ' + {do not localize}
'ORDER BY RDB$GENERATOR_NAME'; {do not localize}
GeneratorNameSQL =
'SELECT RDB$GENERATOR_NAME ' + {do not localize}
'FROM RDB$GENERATORS ' + {do not localize}
'WHERE RDB$GENERATOR_NAME = :GeneratorName AND ' + {do not localize}
' (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG <> 1) ' + {do not localize}
'ORDER BY RDB$GENERATOR_NAME'; {do not localize}
var
qryGenerator : TIBSQL;
GenName : String;
begin
qryGenerator := CreateIBSQL;
try
if GeneratorName = '' then {do not localize}
qryGenerator.SQL.Text := GeneratorSQL
else
begin
qryGenerator.SQL.Text := GeneratorNameSQL;
qryGenerator.Params.ByName('GeneratorName').AsTrimString := GeneratorName; {do not localize}
end;
qryGenerator.ExecQuery;
FMetaData.Add(''); {do not localize}
while not qryGenerator.Eof do
begin
GenName := qryGenerator.FieldByName('RDB$GENERATOR_NAME').AsTrimString; {do not localize}
if ((Pos('RDB$',GenName) = 1) and {do not localize}
(GenName[5] in ['0'..'9'])) or {do not localize}
((Pos('SQL$',GenName) = 1) and {do not localize}
(GenName[5] in ['0'..'9'])) then {do not localize}
begin
qryGenerator.Next;
continue;
end;
FMetaData.Add(Format('CREATE GENERATOR %s%s', {do not localize}
[QuoteIdentifier(FDatabase.SQLDialect, GenName),
Term]));
qryGenerator.Next;
end;
finally
qryGenerator.Free;
end;
end;
{ ListIndex
Functional description
Define all non-constraint indices
Use a static SQL query to get the info and print it.
Uses get_index_segment to provide a key list for each index }
procedure TIBExtract.ListIndex(ObjectName : String; ExtractType : TExtractType);
const
IndexSQL =
'SELECT IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, IDX.RDB$UNIQUE_FLAG, ' + {do not localize}
' IDX.RDB$INDEX_TYPE ' + {do not localize}
'FROM RDB$INDICES IDX JOIN RDB$RELATIONS RELC ON ' + {do not localize}
' IDX.RDB$RELATION_NAME = RELC.RDB$RELATION_NAME ' + {do not localize}
'WHERE (RELC.RDB$SYSTEM_FLAG <> 1 OR RELC.RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' NOT EXISTS (SELECT * FROM RDB$RELATION_CONSTRAINTS RC ' + {do not localize}
' WHERE RC.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME) ' + {do not localize}
'ORDER BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME'; {do not localize}
IndexNameSQL =
'SELECT IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, IDX.RDB$UNIQUE_FLAG, ' + {do not localize}
' IDX.RDB$INDEX_TYPE ' + {do not localize}
'FROM RDB$INDICES IDX JOIN RDB$RELATIONS RELC ON ' + {do not localize}
' IDX.RDB$RELATION_NAME = RELC.RDB$RELATION_NAME ' + {do not localize}
'WHERE (RELC.RDB$SYSTEM_FLAG <> 1 OR RELC.RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' RELC.RDB$RELATION_NAME = :RelationName AND ' + {do not localize}
' NOT EXISTS (SELECT * FROM RDB$RELATION_CONSTRAINTS RC ' + {do not localize}
' WHERE RC.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME) ' + {do not localize}
'ORDER BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME'; {do not localize}
IndexByNameSQL =
'SELECT IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME, IDX.RDB$UNIQUE_FLAG, ' + {do not localize}
' IDX.RDB$INDEX_TYPE ' + {do not localize}
'FROM RDB$INDICES IDX JOIN RDB$RELATIONS RELC ON ' + {do not localize}
' IDX.RDB$RELATION_NAME = RELC.RDB$RELATION_NAME ' + {do not localize}
'WHERE (RELC.RDB$SYSTEM_FLAG <> 1 OR RELC.RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' IDX.RDB$INDEX_NAME = :IndexName AND ' + {do not localize}
' NOT EXISTS (SELECT * FROM RDB$RELATION_CONSTRAINTS RC ' + {do not localize}
' WHERE RC.RDB$INDEX_NAME = IDX.RDB$INDEX_NAME) ' + {do not localize}
'ORDER BY IDX.RDB$RELATION_NAME, IDX.RDB$INDEX_NAME'; {do not localize}
var
qryIndex : TIBSQL;
First : Boolean;
Unique, IdxType, Line : String;
begin
First := true;
qryIndex := CreateIBSQL;
try
if ObjectName = '' then {do not localize}
qryIndex.SQL.Text := IndexSQL
else
begin
if ExtractType = etTable then
begin
qryIndex.SQL.Text := IndexNameSQL;
qryIndex.Params.ByName('RelationName').AsTrimString := ObjectName; {do not localize}
end
else
begin
qryIndex.SQL.Text := IndexByNameSQL;
qryIndex.Params.ByName('IndexName').AsTrimString := ObjectName; {do not localize}
end;
end;
qryIndex.ExecQuery;
while not qryIndex.Eof do
begin
if First then
begin
if ObjectName = '' then {do not localize}
FMetaData.Add(NEWLINE + '/* Index definitions for all user tables */' + NEWLINE) {do not localize}
else
FMetaData.Add(NEWLINE + '/* Index definitions for ' + ObjectName + ' */' + NEWLINE); {do not localize}
First := false;
end; //end_if
if qryIndex.FieldByName('RDB$UNIQUE_FLAG').AsInteger = 1 then {do not localize}
Unique := ' UNIQUE' {do not localize}
else
Unique := ''; {do not localize}
if qryIndex.FieldByName('RDB$INDEX_TYPE').AsInteger = 1 then {do not localize}
IdxType := ' DESCENDING' {do not localize}
else
IdxType := ''; {do not localize}
Line := Format('CREATE%s%s INDEX %s ON %s(', [Unique, IdxType, {do not localize}
QuoteIdentifier(FDataBase.SQLDialect,
qryIndex.FieldByName('RDB$INDEX_NAME').AsTrimString), {do not localize}
QuoteIdentifier(FDataBase.SQLDialect,
qryIndex.FieldByName('RDB$RELATION_NAME').AsTrimString)]); {do not localize}
Line := Line + GetIndexSegments(qryIndex.FieldByName('RDB$INDEX_NAME').AsTrimString) + {do not localize}
')' + Term; {do not localize}
FMetaData.Add(Line);
qryIndex.Next;
end;
finally
qryIndex.Free;
end;
end;
{ ListViews
Functional description
Show text of views.
Use a SQL query to get the info and print it.
Note: This should also contain check option }
procedure TIBExtract.ListViews(ViewName : String);
const
ViewSQL =
'SELECT RDB$RELATION_NAME, RDB$OWNER_NAME, RDB$VIEW_SOURCE ' + {do not localize}
'FROM RDB$RELATIONS ' + {do not localize}
'WHERE ' + {do not localize}
' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' NOT RDB$VIEW_BLR IS NULL AND ' + {do not localize}
' RDB$FLAGS = 1 ' + {do not localize}
'ORDER BY RDB$RELATION_ID'; {do not localize}
ViewNameSQL =
'SELECT RDB$RELATION_NAME, RDB$OWNER_NAME, RDB$VIEW_SOURCE ' + {do not localize}
'FROM RDB$RELATIONS ' + {do not localize}
'WHERE ' + {do not localize}
' (RDB$SYSTEM_FLAG <> 1 OR RDB$SYSTEM_FLAG IS NULL) AND ' + {do not localize}
' NOT RDB$VIEW_BLR IS NULL AND ' + {do not localize}
' RDB$FLAGS = 1 AND ' + {do not localize}
' RDB$RELATION_NAME = :ViewName ' + {do not localize}
'ORDER BY RDB$RELATION_ID'; {do not localize}
ColumnSQL =
'SELECT RDB$FIELD_NAME FROM RDB$RELATION_FIELDS ' + {do not localize}
'WHERE ' + {do not localize}
' RDB$RELATION_NAME = :RELATION_NAME ' + {do not localize}
'ORDER BY RDB$FIELD_POSITION'; {do not localize}
var
qryView, qryColumns : TIBSQL;
SList : TStrings;
begin
qryView := CreateIBSQL;
qryColumns := CreateIBSQL;
SList := TStringList.Create;
try
if ViewName = '' then {do not localize}
qryView.SQL.Text := ViewSQL
else
begin
qryView.SQL.Text := ViewNameSQL;
qryView.Params.ByName('ViewName').AsTrimString := ViewName; {do not localize}
end;
qryColumns.SQL.Text := ColumnSQL;
qryView.ExecQuery;
while not qryView.Eof do
begin
SList.Add(Format('%s/* View: %s, Owner: %s */%s', {do not localize}
[NEWLINE, qryView.FieldByName('RDB$RELATION_NAME').AsTrimString, {do not localize}
qryView.FieldByName('RDB$OWNER_NAME').AsTrimString, NEWLINE])); {do not localize}
SList.Add(Format('CREATE VIEW %s (', [QuoteIdentifier(FDatabase.SQLDialect, {do not localize}
qryView.FieldByName('RDB$RELATION_NAME').AsTrimString)])); {do not localize}
qryColumns.Params.ByName('RELATION_NAME').AsTrimString := {do not localize}
qryView.FieldByName('RDB$RELATION_NAME').AsTrimString; {do not localize}
qryColumns.ExecQuery;
while not qryColumns.Eof do
begin
SList.Add(' ' + QuoteIdentifier(FDatabase.SQLDialect, {do not localize}
qryColumns.FieldByName('RDB$FIELD_NAME').AsTrimString)); {do not localize}
qryColumns.Next;
if not qryColumns.Eof then
SList.Strings[SList.Count - 1] := SList.Strings[SList.Count - 1] + ', '; {do not localize}
end;
qryColumns.Close;
SList.Text := SList.Text + Format(') AS%s', [NEWLINE]); {do not localize}
if not qryView.FieldByName('RDB$VIEW_SOURCE').IsNull then {do not localize}
SList.Text := SList.Text + qryView.FieldByName('RDB$VIEW_SOURCE').AsTrimString; {do not localize}
SList.Text := SList.Text + Format('%s%s', [Term, NEWLINE]); {do not localize}
FMetaData.AddStrings(SList);
SList.Clear;
qryView.Next;
end;
finally
qryView.Free;
qryColumns.Free;
SList.Free;
end;
end;
{ PrintSet
Functional description
print (using ISQL_printf) the word "SET"
if the first line of the ALTER DATABASE
settings options. Also, add trailing
comma for end of prior line if needed.
uses Print_buffer, a global }
function TIBExtract.PrintSet(var Used: Boolean) : String;
begin
if not Used then
begin
Result := ' SET '; {do not localize}
Used := true;
end
else
Result := Format(', %s ', [NEWLINE]); {do not localize}
end;
{
PrintValidation
Functional description
This does some minor syntax adjustmet for extracting
validation blobs and computed fields.
if it does not start with the word CHECK
if this is a computed field blob,look for () or insert them.
if flag = false, this is a validation clause,
if flag = true, this is a computed field }
function TIBExtract.PrintValidation(ToValidate: String;
flag: Boolean): String;
var
IsSQL : Boolean;
begin
IsSql := false;
Result := ''; {do not localize}
ToValidate := Trim(ToValidate);
if flag then
begin
if ToValidate[1] = '(' then {do not localize}
IsSQL := true;
end
else
if (Pos(ToValidate, 'check') = 1) or (Pos(ToValidate, 'CHECK') = 1) then {do not localize}
IsSQL := TRUE;
if not IsSQL then
begin
if Flag then
Result := Result + '/* ' + ToValidate + ' */' {do not localize}
else
Result := Result + '(' + ToValidate + ')'; {do not localize}
end
else
Result := ToValidate;
end;
procedure TIBExtract.SetDatabase(const Value: TIBDatabase);
begin
if FDatabase <> Value then
begin
FDatabase := Value;
if (not Assigned(FTransaction)) and (FDatabase <> nil) then
Transaction := FDatabase.DefaultTransaction;
FDatabaseInfo.Database := FDatabase;
end;
end;
procedure TIBExtract.SetTransaction(const Value: TIBTransaction);
begin
if FTransaction <> Value then
begin
FTransaction := Value;
if (not Assigned(FDatabase)) and (FTransaction <> nil) then
Database := FTransaction.DefaultDatabase;
end;
end;
procedure TIBExtract.ExtractObject(ObjectType : TExtractObjectTypes;
ObjectName : String = ''; ExtractTypes : TExtractTypes = []);
var
DidActivate : Boolean;
begin
DidActivate := false;
if not FTransaction.Active then
begin
FTransaction.StartTransaction;
DidActivate := true;
end;
FMetaData.Clear;
case ObjectType of
eoDatabase : ExtractDDL(true, '');
eoDomain :
if etTable in ExtractTypes then
ListDomains(ObjectName, etTable)
else
ListDomains(ObjectName);
eoTable :
begin
if ObjectName <> '' then
begin
if etDomain in ExtractTypes then
ListDomains(ObjectName, etTable);
ExtractListTable(ObjectName, '', false);
if etIndex in ExtractTypes then
ListIndex(ObjectName, etTable);
if etForeign in ExtractTypes then
ListForeign(ObjectName, etTable);
if etCheck in ExtractTypes then
ListCheck(ObjectName, etTable);
if etTrigger in ExtractTypes then
ListTriggers(ObjectName, etTable);
if etGrant in ExtractTypes then
ShowGrants(ObjectName, Term);
if etData in ExtractTypes then
ListData(ObjectName);
end
else
ListAllTables(true);
end;
eoView :
begin
ListViews(ObjectName);
if etTrigger in ExtractTypes then
ListTriggers(ObjectName, etTable);
end;
eoProcedure : ListProcs(ObjectName, (etAlterProc in ExtractTypes));
eoFunction : ListFunctions(ObjectName);
eoGenerator : ListGenerators(ObjectName);
eoException : ListException(ObjectName);
eoBLOBFilter : ListFilters(ObjectName);
eoRole : ListRoles(ObjectName);
eoTrigger :
if etTable in ExtractTypes then
ListTriggers(ObjectName, etTable)
else
ListTriggers(ObjectName);
eoForeign :
if etTable in ExtractTypes then
ListForeign(ObjectName, etTable)
else
ListForeign(ObjectName);
eoIndexes :
if etTable in ExtractTypes then
ListIndex(ObjectName, etTable)
else
ListIndex(ObjectName);
eoChecks :
if etTable in ExtractTypes then
ListCheck(ObjectName, etTable)
else
ListCheck(ObjectName);
eoData : ListData(ObjectName);
end;
if DidActivate then
FTransaction.Commit;
end;
function TIBExtract.GetFieldType(FieldType, FieldSubType, FieldScale,
FieldSize, FieldPrec, FieldLen: Integer): String;
var
i : Integer;
PrecisionKnown : Boolean;
begin
Result := '';
for i := Low(ColumnTypes) to High(ColumnTypes) do
if FieldType = ColumnTypes[i].SQLType then
begin
PrecisionKnown := FALSE;
if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
begin
if FieldType in [blr_short, blr_long, blr_int64] then
begin
{ We are ODS >= 10 and could be any Dialect }
if (FDatabaseInfo.DBSQLDialect >= 3) and
(FieldPrec <> 0) and
(FieldSubType > 0) and
(FieldSubType <= MAX_INTSUBTYPES) then
begin
Result := Result + Format('%s(%d, %d)', [ {do not localize}
IntegralSubtypes [FieldSubType],
FieldPrec,
-1 * FieldScale]);
PrecisionKnown := true;
end;
end;
end;
if PrecisionKnown = false then
begin
{ Take a stab at numerics and decimals }
if (FieldType = blr_short) and
(FieldScale < 0) then
Result := Result + Format('NUMERIC(4, %d)', {do not localize}
[-FieldScale] )
else
if (FieldType = blr_long) and
(FieldScale < 0) then
Result := Result + Format('NUMERIC(9, %d)', {do not localize}
[-FieldScale] )
else
if (FieldType = blr_double) and
(FieldScale < 0) then
Result := Result + Format('NUMERIC(15, %d)', {do not localize}
[-FieldScale] )
else
Result := Result + ColumnTypes[i].TypeName;
end;
break;
end;
if (FieldType in [blr_text, blr_varying]) and
(FieldSize <> 0) then
Result := Result + Format('(%d)', [FieldSize]); {do not localize}
end;
{ S H O W _ g r a n t s
Functional description
Show grants for given object name
This function is also called by extract for privileges.
It must extract granted privileges on tables/views to users,
- these may be compound, so put them on the same line.
Grant execute privilege on procedures to users
Grant various privilegs to procedures.
All privileges may have the with_grant option set. }
procedure TIBExtract.ShowGrants(MetaObject, Terminator: String);
const
{ This query only finds tables, eliminating owner privileges }
OwnerPrivSQL =
'SELECT PRV.RDB$USER, PRV.RDB$GRANT_OPTION, PRV.RDB$FIELD_NAME, ' + {do not localize}
' PRV.RDB$USER_TYPE, PRV.RDB$PRIVILEGE ' + {do not localize}
'FROM RDB$USER_PRIVILEGES PRV, RDB$RELATIONS REL ' + {do not localize}
'WHERE ' + {do not localize}
' PRV.RDB$RELATION_NAME = :METAOBJECT AND ' + {do not localize}
' REL.RDB$RELATION_NAME = :METAOBJECT AND ' + {do not localize}
' PRV.RDB$PRIVILEGE <> ''M'' AND ' + {do not localize}
' REL.RDB$OWNER_NAME <> PRV.RDB$USER ' + {do not localize}
'ORDER BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION'; {do not localize}
ProcPrivSQL =
'SELECT PRV.RDB$USER, PRV.RDB$GRANT_OPTION, PRV.RDB$FIELD_NAME, ' + {do not localize}
' PRV.RDB$USER_TYPE, PRV.RDB$PRIVILEGE, PRV.RDB$RELATION_NAME ' + {do not localize}
'FROM RDB$USER_PRIVILEGES PRV, RDB$PROCEDURES PRC ' + {do not localize}
'where ' + {do not localize}
' PRV.RDB$OBJECT_TYPE = 5 AND ' + {do not localize}
' PRV.RDB$RELATION_NAME = :METAOBJECT AND ' + {do not localize}
' PRC.RDB$PROCEDURE_NAME = :METAOBJECT AND ' + {do not localize}
' PRV.RDB$PRIVILEGE = ''X'' AND ' + {do not localize}
' PRC.RDB$OWNER_NAME <> PRV.RDB$USER ' + {do not localize}
'ORDER BY PRV.RDB$USER, PRV.RDB$FIELD_NAME, PRV.RDB$GRANT_OPTION'; {do not localize}
RolePrivSQL =
'SELECT * FROM RDB$USER_PRIVILEGES ' + {do not localize}
'WHERE ' + {do not localize}
' RDB$OBJECT_TYPE = 13 AND ' + {do not localize}
' RDB$USER_TYPE = 8 AND ' + {do not localize}
' RDB$RELATION_NAME = :METAOBJECT AND ' + {do not localize}
' RDB$PRIVILEGE = ''M'' ' + {do not localize}
'ORDER BY RDB$USER'; {do not localize}
var
PrevUser, PrevField, WithOption,
PrivString, ColString, UserString,
FieldName, User : String;
c : Char;
PrevOption, PrivFlags, GrantOption : Integer;
First, PrevFieldNull : Boolean;
qryOwnerPriv : TIBSQL;
{ Given a bit-vector of privileges, turn it into a
string list. }
function MakePrivString(cflags : Integer) : String;
var
i : Integer;
begin
for i := Low(PrivTypes) to High(PrivTypes) do
begin
if (cflags and PrivTypes[i].PrivFlag) <> 0 then
begin
if Result <> '' then {do not localize}
Result := Result + ', '; {do not localize}
Result := Result + PrivTypes[i].PrivString;
end; //end_if
end; //end_for
end; //end_fcn MakePrivDtring
begin
if MetaObject = '' then
exit;
First := true;
PrevOption := -1;
PrevUser := '';
PrivString := '';
ColString := '';
WithOption := '';
PrivFlags := 0;
PrevFieldNull := false;
PrevField := '';
qryOwnerPriv := CreateIBSQL;
try
qryOwnerPriv.SQL.Text := OwnerPrivSQL;
qryOwnerPriv.Params.ByName('metaobject').AsTrimString := MetaObject; {do not localize}
qryOwnerPriv.ExecQuery;
while not qryOwnerPriv.Eof do
begin
{ Sometimes grant options are null, sometimes 0. Both same }
if qryOwnerPriv.FieldByName('RDB$GRANT_OPTION').IsNull then {do not localize}
GrantOption := 0
else
GrantOption := qryOwnerPriv.FieldByName('RDB$GRANT_OPTION').AsInteger; {do not localize}
if qryOwnerPriv.FieldByName('RDB$FIELD_NAME').IsNull then {do not localize}
FieldName := ''
else
FieldName := qryOwnerPriv.FieldByName('RDB$FIELD_NAME').AsTrimString; {do not localize}
User := Trim(qryOwnerPriv.FieldByName('RDB$USER').AsTrimString); {do not localize}
{ Print a new grant statement for each new user or change of option }
if ((PrevUser <> '') and (PrevUser <> User)) or
((Not First) and
(PrevFieldNull <> qryOwnerPriv.FieldByName('RDB$FIELD_NAME').IsNull)) or {do not localize}
((not PrevFieldNull) and (PrevField <> FieldName)) or
((PrevOption <> -1) and (PrevOption <> GrantOption)) then
begin
PrivString := MakePrivString(PrivFlags);
First := false;
FMetaData.Add(Format('GRANT %s%s ON %s TO %s%s%s', [PrivString, {do not localize}
ColString, QuoteIdentifier(FDatabase.SQLDialect, MetaObject),
UserString, WithOption, Terminator]));
{ re-initialize strings }
PrivString := '';
WithOption := '';
ColString := '';
PrivFlags := 0;
end; //end_if
PrevUser := User;
PrevOption := GrantOption;
PrevFieldNull := qryOwnerPriv.FieldByName('RDB$FIELD_NAME').IsNull; {do not localize}
PrevField := FieldName;
case qryOwnerPriv.FieldByName('RDB$USER_TYPE').AsInteger of {do not localize}
obj_relation,
obj_view,
obj_trigger,
obj_procedure,
obj_sql_role:
UserString := QuoteIdentifier(FDatabase.SQLDialect, User);
else
UserString := User;
end; //end_case
case qryOwnerPriv.FieldByName('RDB$USER_TYPE').AsInteger of {do not localize}
obj_view :
UserString := 'VIEW ' + UserString; {do not localize}
obj_trigger :
UserString := 'TRIGGER '+ UserString; {do not localize}
obj_procedure :
UserString := 'PROCEDURE ' + UserString; {do not localize}
end; //end_case
c := qryOwnerPriv.FieldByName('RDB$PRIVILEGE').AsTrimString[1]; {do not localize}
case c of
'S' : PrivFlags := PrivFlags or priv_SELECT; {do not localize}
'I' : PrivFlags := PrivFlags or priv_INSERT; {do not localize}
'U' : PrivFlags := PrivFlags or priv_UPDATE; {do not localize}
'D' : PrivFlags := PrivFlags or priv_DELETE; {do not localize}
'R' : PrivFlags := PrivFlags or priv_REFERENCES; {do not localize}
'X' : ; {do not localize}
{ Execute should not be here -- special handling below }
else
PrivFlags := PrivFlags or priv_UNKNOWN;
end; //end_switch
{ Column level privileges for update only }
if FieldName = '' then
ColString := ''
else
ColString := Format(' (%s)', [QuoteIdentifier(FDatabase.SQLDialect, FieldName)]); {do not localize}
if GrantOption <> 0 then
WithOption := ' WITH GRANT OPTION'; {do not localize}
qryOwnerPriv.Next;
end;
{ Print last case if there was anything to print }
if PrevOption <> -1 then
begin
PrivString := MakePrivString(PrivFlags);
First := false;
FMetaData.Add(Format('GRANT %s%s ON %s TO %s%s%s', [PrivString, {do not localize}
ColString, QuoteIdentifier(FDatabase.SQLDialect, MetaObject),
UserString, WithOption, Terminator]));
{ re-initialize strings }
end; //end_if
qryOwnerPriv.Close;
if First then
begin
{ Part two is for stored procedures only }
qryOwnerPriv.SQL.Text := ProcPrivSQL;
qryOwnerPriv.Params.ByName('metaobject').AsTrimString := MetaObject; {do not localize}
qryOwnerPriv.ExecQuery;
while not qryOwnerPriv.Eof do
begin
First := false;
User := Trim(qryOwnerPriv.FieldByName('RDB$USER').AsTrimString); {do not localize}
case qryOwnerPriv.FieldByName('RDB$USER_TYPE').AsInteger of {do not localize}
obj_relation,
obj_view,
obj_trigger,
obj_procedure,
obj_sql_role:
UserString := QuoteIdentifier(FDatabase.SQLDialect, User);
else
UserString := User;
end; //end_case
case qryOwnerPriv.FieldByName('RDB$USER_TYPE').AsInteger of {do not localize}
obj_view :
UserString := 'VIEW ' + UserString; {do not localize}
obj_trigger :
UserString := 'TRIGGER '+ UserString; {do not localize}
obj_procedure :
UserString := 'PROCEDURE ' + UserString; {do not localize}
end; //end_case
if qryOwnerPriv.FieldByName('RDB$GRANT_OPTION').AsInteger = 1 then {do not localize}
WithOption := ' WITH GRANT OPTION' {do not localize}
else
WithOption := '';
FMetaData.Add(Format('GRANT EXECUTE ON PROCEDURE %s TO %s%s%s', {do not localize}
[QuoteIdentifier(FDatabase.SQLDialect, MetaObject), UserString,
WithOption, terminator]));
qryOwnerPriv.Next;
end;
qryOwnerPriv.Close;
end;
if First then
begin
qryOwnerPriv.SQL.Text := RolePrivSQL;
qryOwnerPriv.Params.ByName('metaobject').AsTrimString := MetaObject; {do not localize}
qryOwnerPriv.ExecQuery;
while not qryOwnerPriv.Eof do
begin
if qryOwnerPriv.FieldByName('RDB$GRANT_OPTION').AsInteger = 1 then {do not localize}
WithOption := ' WITH ADMIN OPTION' {do not localize}
else
WithOption := '';
FMetaData.Add(Format('GRANT %s TO %s%s%s', {do not localize}
[QuoteIdentifier(FDatabase.SQLDialect, qryOwnerPriv.FieldByName('RDB$RELATION_NAME').AsTrimString), {do not localize}
qryOwnerPriv.FieldByName('RDB$USER_NAME').AsTrimString, {do not localize}
WithOption, terminator]));
qryOwnerPriv.Next;
end;
end;
qryOwnerPriv.Close;
finally
qryOwnerPriv.Free;
end;
end;
{ ShowGrantRoles
Functional description
Show grants for given role name
This function is also called by extract for privileges.
All membership privilege may have the with_admin option set. }
procedure TIBExtract.ShowGrantRoles(Terminator: String);
const
RoleSQL =
'SELECT RDB$USER, RDB$GRANT_OPTION, RDB$RELATION_NAME ' + {do not localize}
'FROM RDB$USER_PRIVILEGES ' + {do not localize}
'WHERE ' + {do not localize}
' RDB$OBJECT_TYPE = %d AND ' + {do not localize}
' RDB$USER_TYPE = %d AND ' + {do not localize}
' RDB$PRIVILEGE = ''M'' ' + {do not localize}
'ORDER BY RDB$RELATION_NAME, RDB$USER'; {do not localize}
var
WithOption, UserString : String;
qryRole : TIBSQL;
begin
qryRole := CreateIBSQL;
try
qryRole.SQL.Text := Format(RoleSQL, [obj_sql_role, obj_user]);
qryRole.ExecQuery;
while not qryRole.Eof do
begin
UserString := Trim(qryRole.FieldByName('RDB$USER').AsTrimString); {do not localize}
if (not qryRole.FieldByName('RDB$GRANT_OPTION').IsNull) and {do not localize}
(qryRole.FieldByName('RDB$GRANT_OPTION').AsInteger = 1) then {do not localize}
WithOption := ' WITH ADMIN OPTION' {do not localize}
else
WithOption := '';
FMetaData.Add(Format('GRANT %s TO %s%s%s%s', {do not localize}
[ QuoteIdentifier(FDatabase.SQLDialect, qryRole.FieldByName('RDB$RELATION_NAME').AsTrimString), {do not localize}
UserString, WithOption, Terminator, NEWLINE]));
qryRole.Next;
end;
finally
qryRole.Free;
end;
end;
{ GetProcedureArgs
Functional description
This function extract the procedure parameters and adds it to the
extract file }
procedure TIBExtract.GetProcedureArgs(Proc: String);
const
{ query to retrieve the input parameters. }
ProcHeaderSQL =
'SELECT * ' + {do not localize}
' FROM RDB$PROCEDURE_PARAMETERS PRM JOIN RDB$FIELDS FLD ON ' + {do not localize}
' PRM.RDB$FIELD_SOURCE = FLD.RDB$FIELD_NAME ' + {do not localize}
'WHERE ' + {do not localize}
' PRM.RDB$PROCEDURE_NAME = :PROCNAME AND ' + {do not localize}
' PRM.RDB$PARAMETER_TYPE = :Input ' + {do not localize}
'ORDER BY PRM.RDB$PARAMETER_NUMBER'; {do not localize}
var
FirstTime, PrecisionKnown : Boolean;
Line : String;
qryHeader : TIBSQL;
function FormatParamStr : String;
var
i, CollationID, CharSetID, subtype : Integer;
begin
Result := Format(' %s ', [QuoteIdentifier(FDatabase.SQLDialect, qryHeader.FieldByName('RDB$PARAMETER_NAME').AsTrimString)]); {do not localize}
for i := Low(ColumnTypes) to High(ColumnTypes) do
if qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger = ColumnTypes[i].SQLType then {do not localize}
begin
PrecisionKnown := FALSE;
if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION10 then
begin
if qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_short, blr_long, blr_int64] then {do not localize}
begin
{ We are ODS >= 10 and could be any Dialect }
if (FDatabaseInfo.DBSQLDialect >= 3) and
(not qryHeader.FieldByName('RDB$FIELD_PRECISION').IsNull) and {do not localize}
(qryHeader.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger > 0) and {do not localize}
(qryHeader.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger <= MAX_INTSUBTYPES) then {do not localize}
begin
Result := Result + Format('%s(%d, %d)', [ {do not localize}
IntegralSubtypes [qryHeader.FieldByName('RDB$FIELD_SUB_TYPE').AsInteger], {do not localize}
qryHeader.FieldByName('RDB$FIELD_PRECISION').AsInteger, {do not localize}
-1 * qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger]); {do not localize}
PrecisionKnown := true;
end;
end;
end;
if PrecisionKnown = false then
begin
{ Take a stab at numerics and decimals }
if (qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_short) and {do not localize}
(qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then {do not localize}
Result := Result + Format('NUMERIC(4, %d)', {do not localize}
[-qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger] ) {do not localize}
else
if (qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_long) and {do not localize}
(qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then {do not localize}
Result := Result + Format('NUMERIC(9, %d)', {do not localize}
[-qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger] ) {do not localize}
else
if (qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_double) and {do not localize}
(qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger < 0) then {do not localize}
Result := Result + Format('NUMERIC(15, %d)', {do not localize}
[-qryHeader.FieldByName('RDB$FIELD_SCALE').AsInteger] ) {do not localize}
else
Result := Result + ColumnTypes[i].TypeName;
end;
break;
end;
if qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger in [blr_text, blr_varying] then {do not localize}
Result := Result + Format('(%d)', [GetFieldLength(qryHeader)]); {do not localize}
{ Show international character sets and collations }
if (not qryHeader.FieldByName('RDB$COLLATION_ID').IsNull) or {do not localize}
(not qryHeader.FieldByName('RDB$CHARACTER_SET_ID').IsNull) then {do not localize}
begin
if qryHeader.FieldByName('RDB$COLLATION_ID').IsNull then {do not localize}
CollationId := 0
else
CollationId := qryHeader.FieldByName('RDB$COLLATION_ID').AsInteger; {do not localize}
if qryHeader.FieldByName('RDB$CHARACTER_SET_ID').IsNull then {do not localize}
CharSetId := 0
else
CharSetId := qryHeader.FieldByName('RDB$CHARACTER_SET_ID').AsInteger; {do not localize}
Result := Result + GetCharacterSets(CharSetId, CollationId, false);
end;
if qryHeader.FieldByName('RDB$FIELD_TYPE').AsInteger = blr_blob then
begin
subtype := qryHeader.FieldByName('RDB$FIELD_SUB_TYPE').AsShort; {do not localize}
Result := Result + ' SUB_TYPE '; {do not localize}
if (subtype > 0) and (subtype <= MAXSUBTYPES) then
Result := Result + SubTypes[subtype]
else
Result := Result + IntToStr(subtype);
Result := Result + Format(' SEGMENT SIZE %d', {do not localize}
[qryHeader.FieldByName('RDB$SEGMENT_LENGTH').AsInteger]); {do not localize}
end;
end;
begin
FirstTime := true;
qryHeader := CreateIBSQL;
try
qryHeader.SQL.Text := ProcHeaderSQL;
qryHeader.Params.ByName('procname').AsTrimString := Proc; {do not localize}
qryHeader.Params.ByName('Input').AsInteger := 0; {do not localize}
qryHeader.ExecQuery;
while not qryHeader.Eof do
begin
if FirstTime then
begin
FirstTime := false;
FMetaData.Add('('); {do not localize}
end;
Line := FormatParamStr;
qryHeader.Next;
if not qryHeader.Eof then
Line := Line + ','; {do not localize}
FMetaData.Add(Line);
end;
{ If there was at least one param, close parens }
if not FirstTime then
begin
FMetaData.Add( ')'); {do not localize}
end;
FirstTime := true;
qryHeader.Close;
qryHeader.Params.ByName('Input').AsInteger := 1; {do not localize}
qryHeader.ExecQuery;
while not qryHeader.Eof do
begin
if FirstTime then
begin
FirstTime := false;
FMetaData.Add('RETURNS' + NEWLINE + '('); {do not localize}
end;
Line := FormatParamStr;
qryHeader.Next;
if not qryHeader.Eof then
Line := Line + ','; {do not localize}
FMetaData.Add(Line);
end;
{ If there was at least one param, close parens }
if not FirstTime then
begin
FMetaData.Add( ')'); {do not localize}
end;
FMetaData.Add('AS'); {do not localize}
finally
qryHeader.Free;
end;
end;
procedure TIBExtract.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
if (AComponent = FDatabase) and (Operation = opRemove) then
FDatabase := nil;
if (AComponent = FTransaction) and (Operation = opRemove) then
FTransaction := nil;
end;
procedure TIBExtract.ListData(ObjectName: String);
const
SelectSQL = 'SELECT * FROM %s'; {do not localize}
var
qrySelect : TIBSQL;
Line : String;
i : Integer;
begin
qrySelect := CreateIBSQL;
try
qrySelect.SQL.Text := Format(SelectSQL,
[QuoteIdentifier(FDatabase.SQLDialect, ObjectName)]);
qrySelect.ExecQuery;
while not qrySelect.Eof do
begin
Line := 'INSERT INTO ' + QuoteIdentifier(FDatabase.SQLDialect, ObjectName) + ' ('; {do not localize}
for i := 0 to qrySelect.Current.Count - 1 do
if (qrySelect.Fields[i].SQLType <> SQL_ARRAY) and
(qrySelect.Fields[i].SQLType <> SQL_BLOB) then
begin
Line := Line + QuoteIdentifier(FDatabase.SQLDialect, qrySelect.Fields[i].Name);
if i <> (qrySelect.Current.Count - 1) then
Line := Line + ', '; {do not localize}
end;
Line := Line + ') VALUES ('; {do not localize}
for i := 0 to qrySelect.Current.Count - 1 do
begin
if qrySelect.Fields[i].IsNull and
(qrySelect.Fields[i].SQLType <> SQL_ARRAY) and
(qrySelect.Fields[i].SQLType <> SQL_BLOB) then
begin
Line := Line + 'NULL'; {do not localize}
if i <> (qrySelect.Current.Count - 1) then
Line := Line + ', '; {do not localize}
end
else
case qrySelect.Fields[i].SQLType of
SQL_TEXT, SQL_VARYING, SQL_TYPE_DATE,
SQL_TYPE_TIME, SQL_TIMESTAMP :
begin
Line := Line + QuotedStr(qrySelect.Fields[i].AsTrimString);
if i <> (qrySelect.Current.Count - 1) then
Line := Line + ', '; {do not localize}
end;
SQL_SHORT, SQL_LONG, SQL_INT64,
SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
begin
Line := Line + qrySelect.Fields[i].AsTrimString;
if i <> (qrySelect.Current.Count - 1) then
Line := Line + ', '; {do not localize}
end;
SQL_ARRAY, SQL_BLOB : ;
else
IBError(ibxeInvalidDataConversion, [nil]);
end;
end;
Line := Line + ')' + Term; {do not localize}
FMetaData.Add(Line);
qrySelect.Next;
end;
finally
qrySelect.Free;
end;
end;
procedure TIBExtract.ListRoles(ObjectName: String);
const
RolesSQL =
'select * from RDB$ROLES ' + {do not localize}
'order by RDB$ROLE_NAME'; {do not localize}
RolesByNameSQL =
'select * from RDB$ROLES ' + {do not localize}
'WHERE RDB$ROLE_NAME = :RoleName ' + {do not localize}
'order by RDB$ROLE_NAME'; {do not localize}
var
qryRoles : TIBSQL;
PrevOwner, RoleName, OwnerName : String;
begin
{Process GRANT roles}
qryRoles := CreateIBSQL;
try
if FDatabaseInfo.ODSMajorVersion >= ODS_VERSION9 then
begin
PrevOwner := '';
FMetaData.Add('');
FMetaData.Add('/* Grant Roles for this database */'); {do not localize}
FMetaData.Add('');
if ObjectName = '' then
qryRoles.SQL.Text := RolesSQL
else
begin
qryRoles.SQL.Text := RolesByNameSQL;
qryRoles.Params.ByName('RoleName').AsTrimString := ObjectName; {do not localize}
end;
qryRoles.ExecQuery;
try
while not qryRoles.Eof do
begin
RoleName := QuoteIdentifier(FDatabase.SQLDialect,
qryRoles.FieldByName('rdb$Role_Name').AsTrimString); {do not localize}
OwnerName := Trim(qryRoles.FieldByName('rdb$Owner_Name').AsTrimString); {do not localize}
if PrevOwner <> OwnerName then
begin
FMetaData.Add('');
FMetaData.Add(Format('/* Role: %s, Owner: %s */', [RoleName, OwnerName])); {do not localize}
FMetaData.Add('');
PrevOwner := OwnerName;
end;
FMetaData.Add('CREATE ROLE ' + RoleName + Term); {do not localize}
qryRoles.Next;
end;
finally
qryRoles.Close;
end;
end;
finally
qryRoles.Free;
end;
end;
function TIBExtract.GetFieldLength(sql: TIBSQL): Integer;
begin
if sql.FieldByName('RDB$CHARACTER_LENGTH').IsNull then {do not localize}
Result := sql.FieldByName('RDB$FIELD_LENGTH').AsInteger {do not localize}
else
Result := sql.FieldByName('RDB$CHARACTER_LENGTH').AsInteger; {do not localize}
end;
function TIBExtract.CreateIBSQL: TIBSQL;
begin
Result := TIBSQL.Create(FDatabase);
if FTransaction <> FDatabase.DefaultTransaction then
Result.Transaction := FTransaction;
end;
end.