//
Unit ads_DBSqlite;
{Copyright(c)2016 Advanced Delphi Systems
Richard Maley
Advanced Delphi Systems
12613 Maidens Bower Drive
Potomac, MD 20854 USA
phone 301-840-1554
dickmaley@advdelphisys.com
The code herein can be used or modified by anyone. Please retain references
to Richard Maley at Advanced Delphi Systems. If you make improvements to the
code please send your improvements to dickmaley@advdelphisys.com so that the
entire Delphi community can benefit. All comments are welcome.
}
(*UnitIndex Master Index Implementation Section Download UnitsDescription: ads_DBSqlite.pas This unit contains the following routines.
Register TQuerySqlite.ClientDatasetSaveChanges TQuerySqlite.GetActive TQuerySqlite.GetDatabase TQuerySqlite.GetFilter TQuerySqlite.GetFiltered TQuerySqlite.GetFilterOptions TQuerySqlite.GetMasterSource TQuerySqlite.GetParamCheck TQuerySqlite.GetReadOnly TQuerySqlite.GetSqlDelete TQuerySqlite.GetSqlInsert TQuerySqlite.GetSqlModify TQuerySqlite.GetSqlSelect TQuerySqlite.SetActive TQuerySqlite.SetDatabase TQuerySqlite.SetFilter TQuerySqlite.SetFiltered TQuerySqlite.SetFilterOptions TQuerySqlite.SetMasterSource TQuerySqlite.SetParamCheck TQuerySqlite.SetReadOnly TQuerySqlite.SetSqlDelete TQuerySqlite.SetSqlInsert TQuerySqlite.SetSqlModify TQuerySqlite.SetSqlSelect
*)
Interface
Uses
Classes,
DISQLite3DataSet,
DISQLite3Database,
Provider,
DBClient,
DB,
DBGrids
;
Type
TSqliteStringArray = Array Of String;
TSqliteCreateTableFieldLines = TSqliteStringArray;
TQuerySqlite = Class(TDataSource)
Private
{Private Section}
Protected
FClientDataSet: TClientDataSet;
FDatabase: TDISQLite3Database;
FDataSet: TDataSet;
FDataSetProvider: TDataSetProvider;
FDISQLite3UniDirQuery: TDISQLite3UniDirQuery;
Function GetActive: Boolean;
Function GetDatabase: TDISQLite3Database;
Function GetFilter: String;
Function GetFiltered: Boolean;
Function GetFilterOptions: TFilterOptions;
Function GetMasterSource: TDataSource;
Function GetParamCheck: Boolean;
Function GetReadOnly: Boolean;
Function GetSqlDelete: WideString;
Function GetSqlInsert: WideString;
Function GetSqlModify: WideString;
Function GetSqlSelect: WideString;
Procedure ClientDatasetSaveChanges(DataSet: TDataSet);
Procedure SetActive(Const Value: Boolean);
Procedure SetDatabase(Const Value: TDISQLite3Database);
Procedure SetFilter(Const Value: String);
Procedure SetFiltered(Const Value: Boolean);
Procedure SetFilterOptions(Const Value: TFilterOptions);
Procedure SetMasterSource(Const Value: TDataSource);
Procedure SetParamCheck(Const Value: Boolean);
Procedure SetReadOnly(Const Value: Boolean);
Procedure SetSqlDelete(Const Value: WideString);
Procedure SetSqlInsert(Const Value: WideString);
Procedure SetSqlModify(Const Value: WideString);
Procedure SetSqlSelect(Const Value: WideString);
Public
Constructor Create(AOwner: TComponent); Override;
Destructor Destroy; Override;
Class Function DBDropTable(DB: TDISQLite3Database; TableName: String): Boolean;
Class Function DBEmptyTable(DB: TDISQLite3Database; TableName: String): Boolean;
Class Function DBNextInteger(DB: TDISQLite3Database; TableName, FieldName: String): Integer;
Class Function GetCreateTableFieldDefLines(DB: TDISQLite3Database; TableName: String): TSqliteCreateTableFieldLines;
Class Function GetCreateTableSQL(DB: TDISQLite3Database; TableName: String): String;
Class Function GetDatabaseCreateScript(DB: TDISQLite3Database): String;
Class Function GetDatabaseCreateScriptArray(DB: TDISQLite3Database): TSqliteStringArray;
Class Function GetMaxFieldWidth(Database: TDISQLite3Database; FieldName, TableName: String): Integer;
Class Function GetStringFieldSize(Const AColumn: TDISQLite3Column; Const AFieldDef: TFieldDef): Integer; Overload;
Class Function GetStringFieldSize(DB: TDISQLite3Database; TableName, FieldName: String): Integer; Overload;
Class Function GetTableNames(DB: TDISQLite3Database): TSqliteStringArray;
Class Function PosLast(SubString, Source: String): Integer;
Class Function PosLastCaseInsensitive(SubString, Source: String): Integer;
Class Procedure AdjustColumnWidths(qry: TQuerySqlite; TableName: String; DBGrid: TDBGrid);
Class Procedure InitFieldDef(Const AColumn: TDISQLite3Column; Const AFieldDef: TFieldDef);
Public
Property CDS: TClientDataset Read FClientDataSet Write FClientDataSet;
Property Provider: TDataSetProvider Read FDataSetProvider Write FDataSetProvider;
Property Query: TDISQLite3UniDirQuery Read FDISQLite3UniDirQuery Write FDISQLite3UniDirQuery;
Published
Property Active: Boolean Read GetActive Write SetActive;
Property Database: TDISQLite3Database Read GetDatabase Write SetDatabase;
Property Filter: String Read GetFilter Write SetFilter;
Property Filtered: Boolean Read GetFiltered Write SetFiltered;
Property FilterOptions: TFilterOptions Read GetFilterOptions Write SetFilterOptions;
Property MasterSource: TDataSource Read GetMasterSource Write SetMasterSource;
Property ParamCheck: Boolean Read GetParamCheck Write SetParamCheck;
Property Read_Only: Boolean Read GetReadOnly Write SetReadOnly;
Property SqlDelete: WideString Read GetSqlDelete Write SetSqlDelete;
Property SqlInsert: WideString Read GetSqlInsert Write SetSqlInsert;
Property SqlModify: WideString Read GetSqlModify Write SetSqlModify;
Property SqlSelect: WideString Read GetSqlSelect Write SetSqlSelect;
End;
Procedure Register;
implementation
Uses
DBConsts,
Dialogs,
SysUtils;
//Unit Description UnitIndex Master Index
Procedure Register;
Begin
RegisterComponents('ads_Sqlite', [TQuerySqlite]);
End;
{ TCustomQuerySqlite }
Constructor TQuerySqlite.Create(AOwner: TComponent);
Begin
Inherited;
FDISQLite3UniDirQuery := TDISQLite3UniDirQuery.Create(self);
FDISQLite3UniDirQuery.OnInitFieldDef := InitFieldDef;
FDataSetProvider := TDataSetProvider.Create(Self);
FDataSetProvider.DataSet := FDISQLite3UniDirQuery;
FDataSetProvider.Name := 'DataSetProvider';
FClientDataSet := TClientDataSet.Create(Self);
FClientDataSet.Name := 'InternalClientDataSet';
FClientDataSet.ProviderName := FDataSetProvider.Name;
FClientDataSet.SetProvider(FDataSetProvider);
FClientDataSet.AfterPost := ClientDatasetSaveChanges;
FClientDataSet.AfterDelete := ClientDatasetSaveChanges;
DataSet := FClientDataSet;
End;
Destructor TQuerySqlite.Destroy;
Begin
FreeAndNil(FDISQLite3UniDirQuery);
FreeAndNil(FDataSetProvider);
FreeAndNil(FClientDataSet);
Inherited;
End;
//Unit Description UnitIndex Master IndexFunction TQuerySqlite.GetActive: Boolean; Begin Result := FClientDataSet.Active; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetDatabase: TDISQLite3Database; Begin Result := FDatabase; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetFilter: String; Begin Result := FClientDataSet.Filter; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetFiltered: Boolean; Begin Result := FClientDataSet.Filtered; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetFilterOptions: TFilterOptions; Begin Result := FClientDataSet.FilterOptions; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetMasterSource: TDataSource; Begin Result := FClientDataSet.MasterSource; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetParamCheck: Boolean; Begin Result := FDISQLite3UniDirQuery.ParamCheck; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetReadOnly: Boolean; Begin Result := FClientDataSet.ReadOnly; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetSqlDelete: WideString; Begin Result := FDISQLite3UniDirQuery.DeleteSQL; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetSqlInsert: WideString; Begin Result := FDISQLite3UniDirQuery.InsertSQL; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetSqlModify: WideString; Begin Result := FDISQLite3UniDirQuery.ModifySQL; End; //Unit Description UnitIndex Master Index
Function TQuerySqlite.GetSqlSelect: WideString; Begin Result := FDISQLite3UniDirQuery.SelectSQL; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.ClientDatasetSaveChanges(DataSet: TDataSet); Begin FClientDataSet.ApplyUpdates(0); End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetActive(Const Value: Boolean); Begin FClientDataSet.Active := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetDatabase(Const Value: TDISQLite3Database); Begin FDatabase := Value; FDISQLite3UniDirQuery.Database := FDatabase; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetFilter(Const Value: String); Begin FClientDataSet.Filter := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetFiltered(Const Value: Boolean); Begin FClientDataSet.Filtered := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetFilterOptions(Const Value: TFilterOptions); Begin FClientDataSet.FilterOptions := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetMasterSource(Const Value: TDataSource); Begin FClientDataSet.MasterSource := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetParamCheck(Const Value: Boolean); Begin FDISQLite3UniDirQuery.ParamCheck := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetReadOnly(Const Value: Boolean); Begin FClientDataSet.ReadOnly := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetSqlDelete(Const Value: WideString); Begin FDISQLite3UniDirQuery.DeleteSQL := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetSqlInsert(Const Value: WideString); Begin FDISQLite3UniDirQuery.InsertSQL := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetSqlModify(Const Value: WideString); Begin FDISQLite3UniDirQuery.ModifySQL := Value; End; //Unit Description UnitIndex Master Index
Procedure TQuerySqlite.SetSqlSelect(Const Value: WideString);
Begin
FDISQLite3UniDirQuery.SelectSQL := Value;
End;
Class Procedure TQuerySqlite.InitFieldDef(Const AColumn: TDISQLite3Column;
Const AFieldDef: TFieldDef);
Begin
If AFieldDef.DataType In [ftString, ftMemo, ftFmtMemo, ftFixedChar, ftWideString,
ftOraClob, ftFixedWideChar, ftWideMemo] Then
Begin
AFieldDef.Size := GetStringFieldSize(AColumn, AFieldDef);
End;
End;
Class Function TQuerySqlite.PosLast(SubString, Source: String): Integer;
Var
sgRevSource: String;
sgRevSubStr: String;
inLenSource: Integer;
inLenSubStr: Integer;
inCounter: Integer;
inPos: Integer;
Begin
Result := 0;
sgRevSource := '';
sgRevSubStr := '';
inLenSource := Length(Source);
inLenSubStr := Length(SubString);
For inCounter := inLenSource Downto 1 Do
sgRevSource := sgRevSource + Copy(Source, inCounter, 1);
For inCounter := inLenSubStr Downto 1 Do
sgRevSubStr := sgRevSubStr + Copy(SubString, inCounter, 1);
inPos := Pos(sgRevSubStr, sgRevSource);
If inPos = 0 Then Exit;
Result := inLenSource - inPos - inLenSubStr + 2;
End;
Class Function TQuerySqlite.PosLastCaseInsensitive(SubString,
Source: String): Integer;
Begin
Result := PosLast(UpperCase(SubString), UpperCase(Source));
End;
Class Function TQuerySqlite.GetCreateTableSQL(DB: TDISQLite3Database; TableName: String): String;
Var
ds: TQuerySqlite;
sgSQL: String;
Begin
Result := '';
Try
ds := TQuerySqlite.Create(Nil);
ds.SqlSelect := 'Select SQL From sqlite_master Where type="table" And Upper("' + TableName + '")=Upper(tbl_name)';
ds.Database := DB;
ds.Active := True;
sgSQL := '';
If ds.FClientDataSet.Bof And ds.FClientDataSet.Eof Then Exit;
sgSQL := ds.FClientDataSet.FieldByName('sql').AsString;
sgSQL := StringReplace(sgSQL, #13 + #10, ' ', [rfReplaceAll]);
Result := sgSQL;
Finally
FreeAndNil(ds);
End;
End;
Class Function TQuerySqlite.GetCreateTableFieldDefLines(DB: TDISQLite3Database;
TableName: String): TSqliteCreateTableFieldLines;
Var
inPos: Integer;
sgSQL: String;
sgTemp: String;
Begin
SetLength(Result, 0);
Try
sgSQL := GetCreateTableSQL(DB, TableName);
If Trim(sgSQL) = '' Then Exit;
inPos := Pos('(', sgSQL);
If inPos = 0 Then Exit;
sgTemp := Copy(sgSQL, inPos + 1, Length(sgSQL) - (inPos + 1) + 1);
inPos := PosLast(')', sgTemp);
If inPos = 0 Then Exit;
sgTemp := Copy(sgTemp, 1, inPos - 1);
sgTemp := Trim(sgTemp);
While True Do
Begin
inPos := Pos(',', sgTemp);
If inPos = 0 Then
Begin
SetLength(Result, Length(Result) + 1);
Result[High(Result)] := sgTemp;
Break;
End
Else
Begin
SetLength(Result, Length(Result) + 1);
Result[High(Result)] := Copy(sgTemp, 1, inPos - 1);
sgTemp := Copy(sgTemp, inPos + 1, Length(sgTemp) - (inPos + 1) + 1);
End;
End;
Except
End;
End;
Class Function TQuerySqlite.GetStringFieldSize(DB: TDISQLite3Database; TableName,
FieldName: String): Integer;
Var
boFound: Boolean;
FieldLine: String;
Fields: TSqliteCreateTableFieldLines;
i: Integer;
inPos: Integer;
inPosSpace: Integer;
sgAfterName: String;
sgAfterType: String;
sgFieldType: String;
sgFieldTypePrefix: String;
sgFieldTypeSize: String;
sgStringTypes: String;
sgTemp: String;
Begin
Result := -1;
sgStringTypes := '|CHAR|CHARACTER|VARCHAR|VARYING CHARACTER|NCHAR|NATIVE CHARACTER|NVARCHAR|TEXT|CLOB|';
Fields := GetCreateTableFieldDefLines(DB, TableName);
boFound := False;
FieldLine := '';
inPosSpace := -1;
For i := 0 To High(Fields) Do
Begin
Fields[i] := Trim(Fields[i]);
inPos := Pos(UpperCase(FieldName), UpperCase(Fields[i]));
If inPos = 0 Then Continue;
inPosSpace := Pos(' ', Fields[i]);
If inPosSpace = 0 Then Continue;
sgTemp := Copy(Fields[i], 1, inPosSpace - 1);
inPos := Pos(UpperCase(FieldName), UpperCase(sgTemp));
If inPos = 0 Then Continue;
FieldLine := UpperCase(Fields[i]);
boFound := True;
End;
If Not boFound Then Exit;
sgAfterName := Trim(Copy(FieldLine, inPosSpace + 1, Length(FieldLine) - (inPosSpace + 1) + 1));
sgAfterType := '';
inPosSpace := Pos(' ', sgAfterName);
If inPosSpace = 0 Then
Begin
sgFieldType := sgAfterName;
sgAfterType := '';
End
Else
Begin
sgFieldType := Copy(sgAfterName, 1, inPosSpace - 1);
sgAfterType := Copy(sgAfterName, inPosSpace + 1, Length(sgAfterName) - (inPosSpace + 1) + 1);
End;
inPos := Pos('(', sgFieldType);
If inPos = 0 Then
Begin
sgFieldTypePrefix := sgFieldType;
sgFieldTypeSize := '';
End
Else
Begin
sgFieldTypePrefix := Copy(sgFieldType, 1, inPos - 1);
sgFieldTypeSize := Copy(sgFieldType, inPos + 1, Length(sgFieldType) - (inPos + 1) + 1);
sgFieldTypeSize := StringReplace(sgFieldTypeSize, ')', '', [rfReplaceAll]);
End;
inPos := Pos('|' + sgFieldTypePrefix + '|', sgStringTypes);
If inPos <> 0 Then
Begin
If sgFieldTypeSize = '' Then
Begin
If sgFieldTypePrefix = 'CLOB' Then
Begin
Result := 10000;
End
Else
Begin
Result := 2000;
End;
End
Else
Begin
Try
Result := StrToInt(sgFieldTypeSize);
Except
Result := 2000;
End;
End;
End;
End;
Class Function TQuerySqlite.GetStringFieldSize(Const AColumn: TDISQLite3Column; Const AFieldDef: TFieldDef): Integer;
Var
inPos: Integer;
sgFieldType: String;
sgFieldTypePrefix: String;
sgFieldTypeSize: String;
sgStringTypes: String;
Begin
Result := -1;
sgStringTypes := '|CHAR|CHARACTER|VARCHAR|VARYING CHARACTER|NCHAR|NATIVE CHARACTER|NVARCHAR|TEXT|CLOB|';
sgFieldType := UpperCase(Acolumn.ColumnDeclaration);
inPos := Pos('(', sgFieldType);
If inPos = 0 Then
Begin
sgFieldTypePrefix := sgFieldType;
sgFieldTypeSize := '';
End
Else
Begin
sgFieldTypePrefix := Copy(sgFieldType, 1, inPos - 1);
sgFieldTypeSize := Copy(sgFieldType, inPos + 1, Length(sgFieldType) - (inPos + 1) + 1);
sgFieldTypeSize := StringReplace(sgFieldTypeSize, ')', '', [rfReplaceAll]);
End;
inPos := Pos('|' + sgFieldTypePrefix + '|', sgStringTypes);
If inPos <> 0 Then
Begin
If sgFieldTypeSize = '' Then
Begin
If sgFieldTypePrefix = 'CLOB' Then
Begin
Result := 10000;
End
Else
Begin
Result := 2000;
End;
End
Else
Begin
Try
Result := StrToInt(sgFieldTypeSize);
Except
Result := 2000;
End;
End;
End;
End;
Class Function TQuerySqlite.GetMaxFieldWidth(Database: TDISQLite3Database;
FieldName, TableName: String): Integer;
Var
qry: TQuerySqlite;
Begin
Result := -1;
qry := TQuerySqlite.Create(Nil);
Try
qry.SqlSelect :=
'Select length(' + FieldName + ') As MaxLen from ' + TableName +
' where length(' + FieldName + ')=(select max(length(' + FieldName + '))' +
' from ' + TableName + ')';
qry.Database := Database;
qry.Active := True;
If qry.DataSet.bof And qry.DataSet.eof Then Exit;
qry.DataSet.First();
Result := qry.DataSet.FieldByName('MaxLen').AsInteger;
Finally
FreeAndNil(qry);
End;
End;
Class Procedure TQuerySqlite.AdjustColumnWidths(qry: TQuerySqlite; TableName: String; DBGrid: TDBGrid);
Var
i: Integer;
Begin
If Not qry.Active Then Exit;
If qry.DataSet.Bof And qry.DataSet.EOF Then Exit;
For i := 0 To qry.DataSet.FieldCount - 1 Do
Begin
qry.DataSet.Fields[i].DisplayWidth := TQuerySqlite.GetMaxFieldWidth(qry.Database, qry.DataSet.Fields[i].FieldName, TableName);
DBGrid.Columns.RestoreDefaults;
End;
End;
Class Function TQuerySqlite.GetTableNames(
DB: TDISQLite3Database): TSqliteStringArray;
Var
qry: TQuerySqlite;
Begin
SetLength(Result, 0);
qry := TQuerySqlite.Create(Nil);
Try
qry.SqlSelect :=
'Select tbl_name As TableName From sqlite_master where type="table" Order By tbl_name';
qry.Database := DB;
qry.Active := True;
If qry.DataSet.bof And qry.DataSet.eof Then Exit;
qry.DataSet.First();
While Not qry.DataSet.eof Do
Begin
SetLength(Result, Length(Result) + 1);
Result[High(Result)] := qry.DataSet.FieldByName('TableName').AsString;
qry.DataSet.Next();
End;
Finally
FreeAndNil(qry);
End;
End;
Class Function TQuerySqlite.GetDatabaseCreateScript(
DB: TDISQLite3Database): String;
Var
i: Integer;
a: TSqliteStringArray;
Begin
Result := '';
a := GetDatabaseCreateScriptArray(DB);
For i := 0 To High(a) Do
Begin
Result := Result + a[i] + ';' + #13 + #10 + #13 + #10;
End;
End;
Class Function TQuerySqlite.GetDatabaseCreateScriptArray(
DB: TDISQLite3Database): TSqliteStringArray;
Var
a: TSqliteStringArray;
i: Integer;
s: String;
Begin
a := TQuerySqlite.GetTableNames(DB);
SetLength(Result, 0);
For i := 0 To High(a) Do
Begin
SetLength(Result, Length(Result) + 1);
s := GetCreateTableSQL(DB, a[i]);
Result[High(Result)] := s;
End;
End;
Class Function TQuerySqlite.DBNextInteger(DB: TDISQLite3Database; TableName,
FieldName: String): Integer;
Var
qry: TQuerySqlite;
Begin
Result := 0;
qry := TQuerySqlite.Create(Nil);
Try
If Trim(TableName) = '' Then Exit;
If Trim(FieldName) = '' Then Exit;
Try
qry.SqlSelect :=
'Select Max(' + FieldName + ') As MaxValue From ' + TableName;
qry.Database := DB;
qry.Active := True;
If qry.DataSet.bof And qry.DataSet.eof Then Exit;
qry.DataSet.First();
Result := qry.DataSet.FieldByName('MaxValue').AsInteger + 1;
Except
End;
Finally
FreeAndNil(qry);
End;
End;
Class Function TQuerySqlite.DBDropTable(DB: TDISQLite3Database;
TableName: String): Boolean;
Begin
Result := False;
If Trim(TableName) = '' Then Exit;
Try
DB.Execute('Drop Table ' + TableName);
DB.Commit;
Result := True;
Except
End;
End;
Class Function TQuerySqlite.DBEmptyTable(DB: TDISQLite3Database;
TableName: String): Boolean;
Var
sql: String;
Begin
Result := False;
If Trim(TableName) = '' Then Exit;
Try
sql := GetCreateTableSQL(DB, TableName);
DB.Execute('Drop Table ' + TableName);
DB.Commit;
DB.Execute(sql);
DB.Commit;
Result := True;
Except
End;
End;
End.
//