There is a sqlite database - a descriptor containing a list of tables, a list of domains, a list of fields, a list of constraints (primary and foreign keys), a list of indices. I connect from Delphi XE3 using the embedded component to this database. There is a separate module in which the classes TTableSpec, TFieldSpec, TConstraintSpec, TConstraintDetSpec are described. These classes correspond to entries in the above sqlite database. In classes of type TTableSpec there are such fields of type FFields : TComponent
, which is made by the owner of objects of type TFieldSpec, also unloaded from the database. After creating objects by reading the descriptor base, I found that the values of some properties of objects (for example, TFieldSpec) are not in the same encoding (line Edit2.Text:=TFieldSpec(TConstraintDetailSpec(TConstraintSpec(TTableSpec(DBSchema.Tables.FindComponent(InputTableName)).Constraints.Components[i]).DetailList).FieldSpec).FieldName;
in the following function, check that the field is the primary key of this table).
function TfmSettings.IsPrimaryKey(InputTableName : string; InputFieldName: string):Boolean; var i : integer; flag: boolean; begin flag:=False; for i:=0 to TTableSpec(DBSchema.Tables.FindComponent(InputTableName)).Constraints.ComponentCount-1 do begin if ((TConstraintSpec(TTableSpec(DBSchema.Tables.FindComponent(InputTableName)).Constraints.Components[i]).ConstraintType='PRIMARY') and (TTableSpec(DBSchema.Tables.FindComponent(InputTableName)).Fields.FindComponent(InputFieldName).Name=TConstraintDetailSpec(TConstraintSpec(TTableSpec(DBSchema.Tables.FindComponent(InputTableName)).Constraints.Components[i]).DetailList).FieldName)) then flag:=True; Edit1.Text:=TConstraintSpec(TTableSpec(DBSchema.Tables.FindComponent(InputTableName)).Constraints.Components[i]).Name; Edit2.Text:=TFieldSpec(TConstraintDetailSpec(TConstraintSpec(TTableSpec(DBSchema.Tables.FindComponent(InputTableName)).Constraints.Components[i]).DetailList).FieldSpec).FieldName; Edit3.Text:=InputFieldName; end; Result:=flag; end;
I also give the code of procedures that create objects related to incorrect encoding:
procedure CreationListOfFields(SQLConn: TSQLConnection; DBSchema : TDBSchemaSpec); var NameField : TField; PositionField : TField; DescriptionField : TField; CanInputField : TField; CanEditField : TField; ShowInGridField : TField; ShowInDetailsField : TField; IsMeanField : TField; AutocalculatedField : TField; RequiredField : TField; Name1 : TField; Name2 : TField; begin SQLConn.Execute('select f.id, f.position, f.name, f.description, f.can_input, ' +' f.can_edit, f.show_in_grid, f.show_in_details, f.is_mean, f.autocalculated, f.required, t.name, d.name ' +' from fields f left join tables t on f.table_id=t.id ' +' left join domains d on f.domain_id=d.id order by t.name, d.name ', nil, results); if not results.IsEmpty then begin results.First; Name1:=results.FieldByName('name_1'); Name2:=results.FieldByName('name_2'); lastTable:=Name1.AsString; TableSpec:=TTableSpec(DBSchema.Tables.FindComponent(lastTable)); lastDomain:=Name2.AsString; DomainSpec:=TDomainSpec(DBSchema.Domains.FindComponent(lastDomain)); NameField:=results.FieldByName('name'); PositionField:=results.FieldByName('position'); DescriptionField:=results.FieldByName('description'); CanInputField:=results.FieldByName('can_input'); CanEditField:=results.FieldByName('can_edit'); ShowInGridField:=results.FieldByName('show_in_grid'); ShowInDetailsField:=results.FieldByName('show_in_details'); IsMeanField:=results.FieldByName('is_mean'); AutocalculatedField:=results.FieldByName('autocalculated'); RequiredField:=results.FieldByName('required'); while not results.Eof do begin if (Name1.AsString<>lastTable) then begin lastTable:=Name1.AsString; TableSpec:=TTableSpec(DBSchema.Tables.FindComponent(lastTable)); end; if (Name2.AsString<>lastDomain) then begin lastDomain:=Name2.AsString; DomainSpec:=TDomainSpec(DBSchema.Domains.FindComponent(lastDomain)); end; FieldSpec:=TFieldSpec.Create(TableSpec.Fields); FieldSpec.Setup( DomainSpec, PositionField.AsInteger, NameField.AsString, DescriptionField.AsString, FieldToBoolean(CanInputField),FieldToBoolean(CanEditField), FieldToBoolean(ShowInGridField), FieldToBoolean(ShowInDetailsField), FieldToBoolean(IsMeanField),FieldToBoolean(AutocalculatedField), FieldToBoolean(RequiredField)); TComponent(FieldSpec).Name:=NameField.AsString; TableSpec.Fields.InsertComponent(FieldSpec); results.Next; end; end; end; procedure CreationListOfConstrAndConstrDet(SQLConn : TSQLConnection; DBSchema : TDBSchemaSpec); var IDField : TField; NameField : TField; ConstrTypeField : TField; ReferenceField : TField; UniqueKeyIdField : TField; HasValueEditField : TField; CascadingDeleteField: TField; ExpressionField : TField; NameField1 : TField; Name1 : TField; begin SQLConn.Execute('select c.id, c.name, constraint_type, reference, unique_key_id, has_value_edit, ' + 'cascading_delete, expression, t.name from constraints c left join tables t on c.table_id=t.id order' +' by t.name ', nil, results); if not results.IsEmpty then begin results.First; IDField:=results.FieldByName('ID'); NameField:=results.FieldByName('name'); ConstrTypeField:=results.FieldByName('constraint_type'); ReferenceField:=results.FieldByName('reference'); UniqueKeyIdField:=results.FieldByName('unique_key_id'); HasValueEditField:=results.FieldByName('has_value_edit'); CascadingDeleteField:=results.FieldByName('cascading_delete'); ExpressionField:=results.FieldByName('expression'); Name1:=results.FieldByName('name_1'); lastTable:=Name1.AsString; TableSpec:=TTableSpec(DBSchema.Tables.FindComponent(lastTable)); while not results.Eof do begin if (Name1.AsString<>lastTable) then begin lastTable:=Name1.AsString; TableSpec:=TTableSpec(DBSchema.Tables.FindComponent(lastTable)); end; ConstraintSpec:=TConstraintSpec.Create(TableSpec.Constraints); ConstraintSpec.Setup(IDField.AsInteger,NameField.AsString, ConstrTypeField.AsString, ReferenceField.AsString, ConvertToInt(UniqueKeyIdField.AsString), FieldToBoolean(HasValueEditField), FieldToBoolean(CascadingDeleteField), ExpressionField.AsString); TComponent(ConstraintSpec).Name:=results.FieldByName('name').AsString; TableSpec.Constraints.InsertComponent(ConstraintSpec); SQLConn.Execute('select cd.id, f.name from constraint_details cd left join' +' fields f on f.id=cd.field_id where cd.constraint_id = '+inttostr(ConstraintSpec.ID), nil, results1); if not results1.IsEmpty then begin results1.First; NameField1:=results1.FieldByName('name'); while not results1.Eof do begin FieldSpec:=TFieldSpec(TableSpec.Fields.FindComponent(NameField1.AsString)); ConstDetSpec:=TConstraintDetailSpec.Create(ConstraintSpec.DetailList); ConstDetSpec.Setup(NameField1.AsString, FieldSpec); ConstraintSpec.DetailList.InsertComponent(ConstDetSpec); results1.Next; end; end; results.Next; end; end; end;
PS SQL queries are executed in sqlite normally. Produces the necessary lines in the necessary coding (at least visually the result contains readable English and Russian characters). I also give the class code:
unit DatabaseClasses; interface uses Classes; type TDataTypeId = (DataTypeId_String, DataTypeId_SmallInt, DataTypeId_Integer, DataTypeId_Word, DataTypeId_Boolean, DataTypeId_Float, DataTypeId_Currency, DataTypeId_BCD, DataTypeId_FmtBCD, DataTypeId_Date, DataTypeId_Time, DataTypeId_DateTime, DataTypeId_TimeStamp, DataTypeId_Bytes, DataTypeId_VarBytes, DataTypeId_Blob, DataTypeId_Memo, DataTypeId_Graphic, DataTypeId_fmtMemo, DataTypeId_FixedChar, DataTypeId_WideChar, DataTypeId_LargeInt, DataTypeId_Array, DataTypeId_FixedWideChar, DataTypeId_WideMemo); TAlignSpec = (AlignSpec_Left, AlignSpec_Right, AlignSpec_Center); TFieldSpec=class; TConstraintDetailSpec = class; TIndexDetailSpec = class; TDBSchemaSpec=class(Tcomponent) private FDomains: TComponent; FTables : TComponent; public procedure Setup(); destructor Destroy; override; property Domains: TComponent read FDomains; property Tables : TComponent read FTables; end; TDomainSpec = class(TComponent) private FName: string; FDescription: String; FDataTypeId: TDataTypeId; FLength: Cardinal; FCharLength: Cardinal; FPrecision: Cardinal; FScale: Cardinal; FWidth: Word; FAlign: TAlignSpec; FShowNull: Boolean; FShowLeadNulls: Boolean; FThousandsSeparator: Boolean; public procedure Setup(FName: string; FDescription: String; FDataTypeId: TDataTypeId; FLength: Cardinal;FCharLength: Cardinal;FPrecision: Cardinal;FScale: Cardinal; FWidth: Word;FAlign: TAlignSpec;FShowNull: Boolean;FShowLeadNulls: Boolean; FThousandsSeparator: Boolean); destructor Destroy; override; property Name: String read FName; property Description: String read FDescription; property DataTypeId: TDataTypeId read FDataTypeId; property Length: Cardinal read FLength; property CharLength: Cardinal read FCharLength; property Precision: Cardinal read FPrecision; property Scale: Cardinal read FScale; property Width: Word read FWidth; property Align: TAlignSpec read FAlign; property ShowNull: Boolean read FShowNull; property ShowLeadNulls: Boolean read FShowLeadNulls; property ThousandsSeparator: Boolean read FThousandsSeparator; end; TTableSpec= class(TComponent) private FFields : TComponent; FIndices: TComponent; FConstraints : TComponent; FName : string; FDescription: string; FCanAdd: boolean; FCanEdit: boolean; FCanDelete: boolean; public procedure Setup(FName : string; FDescription:string; FCanAdd: boolean; FCanEdit: boolean; FCanDelete: boolean); destructor Destroy; override; property Description : string read FDescription; property Name : string read FName; property CanAdd: boolean read FCanAdd; property CanEdit: boolean read FCanEdit; property CanDelete: boolean read FCanDelete; property Fields : TComponent read FFields; property Indices: TComponent read FIndices; property Constraints : TComponent read FConstraints; end; TFieldSpec = class(TComponent) private FDomainSpec: TDomainSpec; FPosition: integer; FFieldName: string; FDescription: string; FCanInput: boolean; FCanEdit: boolean; FShowInGrid: boolean; FShowInDetails: boolean; FIsMean: boolean; FAutoCalculated: boolean; FRequired: boolean; public procedure Setup(FDomainSpec: TDomainSpec; FPosition: integer; FFieldName: string; FDescription: string; FCanInput: boolean; FCanEdit: boolean; FShowInGrid: boolean; FShowInDetails: boolean; FIsMean: boolean;FAutoCalculated: boolean; FRequired: boolean); destructor Destroy; override; property DomainSpec: TDomainSpec read FDomainSpec; property Position: integer read FPosition; property FieldName: string read FFieldName; property Description: string read FDescription; property CanInput: boolean read FCanInput; property CanEdit: boolean read FCanEdit; property ShowInGrid: boolean read FShowInGrid; property ShowInDetails: boolean read FShowInDetails; property IsMean: boolean read FIsMean; property AutoCalculated: boolean read FAutoCalculated; property Required: boolean read FRequired; end; TConstraintSpec = class(TComponent) private FID: integer; FDetails: TComponent; FName: string; FConstraintType: string; FReference: string; FUniqueKeyId: integer; FHasValueEdit: boolean; FCascadingDelete: boolean; FExpression: string; public procedure Setup(FID: integer; FName: string; FConstraintType: string; FReference: string; FUniqueKeyId: integer; FHasValueEdit: boolean; FCascadingDelete: boolean; FExpression: string); destructor Destroy; override; property ID: integer read FID; property Name: string read FName; property ConstraintType: string read FConstraintType; property Reference: string read FReference; property UniqueKeyId: integer read FUniqueKeyId; property HasValueEdit: boolean read FHasValueEdit; property CascadingDelete: boolean read FCascadingDelete; property Expression: string read FExpression; property DetailList: TComponent read FDetails; end; TConstraintDetailSpec = class(TComponent) private FFieldName: string; FFieldSpec: TFieldSpec; public procedure Setup(FFieldName: string; FFieldSpec: TFieldSpec); destructor Destroy; override; property FieldName: string read FFieldName; property FieldSpec: TFieldSpec read FFieldSpec; end; TIndexSpec = class(TComponent) private FDetails: TComponent; FID : integer; FName: string; FUniqueness: boolean; public procedure Setup(FID: integer; FName: string; FUniqueness: boolean ); destructor Destroy; override; property ID : integer read FID; property DetailList:TComponent read FDetails; property Name: string read FName; property Uniqueness: boolean read FUniqueness; end; TIndexDetailSpec = class(TComponent) private FPosition: integer; FFieldSpec: TFieldSpec; FExpression: string; FDescend: boolean; public procedure Setup(FPosition: integer; FFieldSpec: TFieldSpec; FExpression: string; FDescend: boolean ); destructor Destroy; override; property FieldSpec: TFieldSpec read FFieldSpec; property Position: integer read FPosition; property Expression: string read FExpression; property Descend: boolean read FDescend; end; implementation procedure TDBSchemaSpec.Setup; begin FDomains := TComponent.Create(self); FTables := TComponent.Create(self); end; destructor TDBSchemaSpec.Destroy; begin FDomains.Free; FTables.Free; inherited Destroy; end; procedure TDomainSpec.Setup; begin self.FName:=FName; self.FDescription:=FDescription; self.FDataTypeId:=FDataTypeId; self.FLength:=FLength; self.FCharLength:=FCharLength; self.FPrecision:=FPrecision; self.FScale:=FScale; self.FWidth:=FWidth; self.FAlign:=FAlign; self.FShowNull:=FShowNull; self.FShowLeadNulls:=FShowLeadNulls; self.FThousandsSeparator:=FThousandsSeparator; end; destructor TDomainSpec.Destroy; begin inherited Destroy; end; procedure TTableSpec.Setup; begin FFields := TComponent.Create(Self); FConstraints := TComponent.Create(Self); FIndices := TComponent.Create(Self); Self.FName:=FName; self.FDescription:=FDescription; self.FCanAdd:=FCanAdd; self.FCanEdit:=FCanEdit; self.FCanDelete:=FCanDelete; end; destructor TTableSpec.Destroy; begin FFields.Free; FConstraints.Free; FIndices.Free; inherited Destroy; end; procedure TFieldSpec.Setup; begin self.FDomainSpec:=FDomainSpec; self.FPosition:=Fposition; self.FFieldName:=FFieldName; self.FDescription:=FDescription; self.FCanInput:=FCanInput; self.FCanEdit:=FCanEdit; self.FShowInGrid:=FShowInGrid; self.FShowInDetails:=FShowInDetails; self.FIsMean:=FIsMean; self.FAutoCalculated:=FAutoCalculated; self.FRequired:=FRequired; end; destructor TFieldSpec.Destroy; begin inherited Destroy; end; procedure TConstraintSpec.Setup; begin FDetails := TComponent.Create(self); self.FID:=FID; self.FName:=FName; self.FConstraintType:=FConstraintType; self.FReference:=FReference; self.FUniqueKeyId:=FUniqueKeyId; self.FHasValueEdit:=FhasValueEdit; self.FCascadingDelete:=FCascadingDelete; self.FExpression:=FExpression; end; destructor TConstraintSpec.Destroy; begin FDetails.Free; inherited Destroy; end; procedure TConstraintDetailSpec.Setup; begin self.FFieldName:=FFieldName; self.FFieldSpec:=FFieldSpec; end; destructor TConstraintDetailSpec.Destroy; begin inherited Destroy; end; procedure TIndexSpec.Setup; begin FDetails := TComponent.Create(self); self.FID:=FID; self.FName:=FName; self.FUniqueness:=FUniqueness; end; destructor TIndexSpec.Destroy; begin FDetails.Free; inherited Destroy; end; procedure TIndexDetailSpec.setup; begin self.FPosition:=FPosition; self.FFieldSpec:=FFieldSpec; self.FExpression:=FExpression; self.FDescend:=FDescend; end; destructor TIndexDetailSpec.Destroy; begin inherited Destroy; end; end.