2016-06-27 22:43:15 +00:00
{$I vp.inc}
2016-06-14 21:43:21 +00:00
unit VpZeosDs;
interface
uses
2016-06-15 09:42:30 +00:00
SysUtils, Classes, DB,
2023-10-10 22:24:46 +00:00
VpData, VpBaseDS, VpDBDS,
2016-06-14 21:43:21 +00:00
ZCompatibility, ZConnection, ZDataset;
type
2022-04-18 16:48:40 +00:00
{ TVpZeosDatastore }
2016-06-14 21:43:21 +00:00
TVpZeosDatastore = class( TVpCustomDBDatastore)
private
FConnection: TZConnection;
FContactsTable: TZTable;
FEventsTable: TZTable;
FResourceTable: TZTable;
FTasksTable: TZTable;
2022-04-20 23:01:29 +00:00
procedure CreateAutoInc_Firebird( ATableName, AIdFieldName: String ) ;
2016-06-15 09:42:30 +00:00
procedure SetConnection( const AValue: TZConnection) ;
2022-04-18 16:48:40 +00:00
2016-06-14 21:43:21 +00:00
protected
2016-09-19 20:57:45 +00:00
procedure CreateTable( const ATableName: String ; CreateIndex: Boolean = true ) ;
2016-06-17 20:23:56 +00:00
procedure CreateAllTables;
2016-06-14 21:43:21 +00:00
function GetContactsTable: TDataset; override ;
function GetEventsTable: TDataset; override ;
function GetResourceTable: TDataset; override ;
function GetTasksTable: TDataset; override ;
2023-10-10 22:24:46 +00:00
procedure InternalPurgeContacts( Res: TVpResource) ; override ;
procedure InternalPurgeEvents( Res: TVpResource) ; override ;
procedure InternalPurgeTasks( Res: TVpResource) ; override ;
2016-06-14 21:43:21 +00:00
procedure Loaded; override ;
2016-06-15 09:42:30 +00:00
procedure Notification( AComponent: TComponent; Operation: TOperation) ; override ;
2016-06-14 21:43:21 +00:00
procedure SetConnected( const AValue: Boolean ) ; override ;
2018-05-15 23:14:44 +00:00
procedure SetTableConnections( AConnection: TZConnection) ;
2022-06-08 11:09:59 +00:00
function TableExists( ATableName: String ) : Boolean ;
2018-05-15 23:14:44 +00:00
function TablesExist: boolean ;
2016-06-14 21:43:21 +00:00
2022-04-18 16:48:40 +00:00
protected
FIdFieldTypeNameInSQL: String ;
FBoolFieldTypeNameInSQL: String ;
procedure AdjustSQLFieldTypeNames; virtual ;
2016-09-19 20:57:45 +00:00
protected
// Fix old tables
procedure AddField( ATableName, AFieldName: String ; AFieldType: TFieldType;
ASize: Integer = 0 ) ;
procedure RenameFields( ATableName: String ; AFields: TStrings) ;
procedure FixContactsTable;
2016-06-14 21:43:21 +00:00
public
constructor Create( AOwner: TComponent) ; override ;
procedure CreateTables;
2018-01-12 12:42:12 +00:00
function GetNextID( {%H-} TableName: string ) : integer ; override ;
2016-06-14 21:43:21 +00:00
property ResourceTable;
property EventsTable;
property ContactsTable;
property TasksTable;
published
2016-06-15 09:42:30 +00:00
property Connection: TZConnection read FConnection write SetConnection;
2016-06-14 21:43:21 +00:00
// inherited
2016-07-26 09:30:20 +00:00
property AutoConnect default false ;
property AutoCreate default false ;
property Daybuffer;
2016-06-14 21:43:21 +00:00
end ;
implementation
uses
2016-09-19 20:57:45 +00:00
LazFileUtils, ZAbstractDataset,
2018-05-15 23:14:44 +00:00
VpConst, VpException;
2016-06-14 21:43:21 +00:00
{ TVpZeosDatastore }
constructor TVpZeosDatastore. Create( AOwner: TComponent) ;
begin
inherited ;
2018-05-15 23:14:44 +00:00
FAutoCreate : = false ;
2016-06-14 21:43:21 +00:00
FContactsTable : = TZTable. Create( self) ;
2022-06-08 11:09:59 +00:00
FContactsTable. TableName : = ContactsTableName;
2016-09-19 20:57:45 +00:00
FContactsTable. UpdateMode : = umUpdateAll;
2016-06-14 21:43:21 +00:00
FEventsTable : = TZTable. Create( Self) ;
2022-06-08 11:09:59 +00:00
FEventsTable. TableName : = EventsTableName;
2016-09-19 20:57:45 +00:00
FEventsTable. UpdateMode : = umUpdateAll;
2016-06-14 21:43:21 +00:00
FResourceTable : = TZTable. Create( self) ;
2022-06-08 11:09:59 +00:00
FResourceTable. TableName : = ResourceTableName;
2016-09-19 20:57:45 +00:00
FResourceTable. UpdateMode : = umUpdateAll;
2016-06-14 21:43:21 +00:00
FTasksTable : = TZTable. Create( self) ;
2022-06-08 11:09:59 +00:00
FTasksTable. TableName : = TasksTableName;
2016-09-19 20:57:45 +00:00
FTasksTable. UpdateMode : = umUpdateAll;
end ;
procedure TVpZeosDatastore. AddField( ATableName, AFieldName: String ;
AFieldType: TFieldType; ASize: Integer = 0 ) ;
var
ft: String ;
sql: String ;
begin
if AFieldType = ftInteger then
ft : = 'INTEGER' else
if ( AFieldType = ftString) then
ft : = 'VARCHAR(' + intToStr( ASize) + ')'
else
raise Exception. Create( 'Field type not supported here.' ) ;
sql : = Format( 'ALTER TABLE %s ADD COLUMN %s %s;' , [ ATablename, AFieldName, ft] ) ;
FConnection. ExecuteDirect( sql) ;
2016-06-14 21:43:21 +00:00
end ;
2022-04-18 16:48:40 +00:00
{ Select the correct SQL field type names which vary between SQL dialects. }
procedure TVpZeosDatastore. AdjustSQLFieldTypeNames;
var
protocol: String ;
begin
FIdFieldTypeNameInSQL : = 'INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT' ;
FBoolFieldTypeNameInSQL : = 'BOOL' ;
if Assigned( FConnection) then
begin
protocol : = Lowercase( FConnection. Protocol) ;
2022-04-18 21:41:51 +00:00
if protocol = 'firebird' then
begin
2022-04-20 23:01:29 +00:00
// FIdFieldTypeNameInSQL := 'INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY'; // This can be used in Firebird v3 to replace the trigger and generator
FIdFieldTypeNameInSQL : = 'INTEGER NOT NULL PRIMARY KEY' ; // This works for firebird v2.x and v3 when triggers & generators are provided
2022-04-18 21:41:51 +00:00
FBoolFieldTypenameInSQL : = 'BOOLEAN' ;
end else
2023-10-04 20:42:19 +00:00
if pos( 'postgres' , protocol) > 0 then
2022-04-18 16:48:40 +00:00
FIdFieldTypeNameInSQL : = 'SERIAL NOT NULL PRIMARY KEY'
else
if protocol = 'sqlite' then
FIdFieldTypeNameInSQL : = 'INTEGER PRIMARY KEY'
else
if protocol = 'mssql' then
begin
FIdFieldTypeNameInSQL : = 'INTEGER NOT NULL IDENTITY PRIMARY KEY' ;
FBoolFieldTypeNameInSQL : = 'BIT' ;
end else
if protocol = 'mysql' then
FBoolFieldTypeNameInSQL : = 'BIT' ;
end ;
end ;
2016-06-17 20:23:56 +00:00
procedure TVpZeosDatastore. CreateAllTables;
2018-05-15 23:14:44 +00:00
var
wasConnected: Boolean ;
2016-06-14 21:43:21 +00:00
begin
2018-05-15 23:14:44 +00:00
wasConnected : = FConnection. Connected;
try
if FContactsTable. Connection = nil then begin
FConnection. Connected : = false ;
SetTableConnections( FConnection) ;
end ;
FConnection. Connected : = true ;
2022-06-08 11:09:59 +00:00
if not TableExists( ContactsTableName) then CreateTable( ContactsTableName) ;
if not TableExists( EventsTableName) then CreateTable( EventsTableName) ;
if not TableExists( ResourceTableName) then CreateTable( ResourceTableName) ;
if not TableExists( TasksTableName) then CreateTable( TasksTableName) ;
2018-05-15 23:14:44 +00:00
finally
FConnection. Connected : = wasConnected;
end ;
2016-06-14 21:43:21 +00:00
end ;
2022-04-20 23:01:29 +00:00
{ Create generator and trigger for Firebird in order to autoincrement the values
in field AIdFieldName of table ATableName.
http: //firebirdfaq.org/faq29/ }
procedure TVpZeosDatastore. CreateAutoInc_Firebird( ATableName, AIdFieldName: String ) ;
begin
FConnection. ExecuteDirect( Format(
'CREATE GENERATOR gen_%s_id;' , [ ATableName]
) ) ;
FConnection. ExecuteDirect( Format(
'SET GENERATOR gen_%s_id TO 0;' , [ ATableName]
) ) ;
FConnection. ExecuteDirect( Format(
'CREATE TRIGGER %0:s_BI FOR %0:s ' +
'ACTIVE BEFORE INSERT POSITION 0 ' +
'AS ' +
'BEGIN ' +
'if (NEW.%1:s is NULL) then NEW.%1:s = GEN_ID(GEN_%0:s_ID, 1); ' +
'END' , [ ATableName, AIdFieldName]
) ) ;
end ;
2016-09-19 20:57:45 +00:00
procedure TVpZeosDatastore. CreateTable( const ATableName: String ;
CreateIndex: Boolean = true ) ;
2022-04-18 21:41:51 +00:00
var
CREATE_TABLE: String ;
2016-06-14 21:43:21 +00:00
begin
2022-04-18 21:41:51 +00:00
if ( Lowercase( FConnection. Protocol) = 'firebird' ) then
CREATE_TABLE : = 'RECREATE TABLE ' // Not clear if this is correct for firebird v2.x, it is for fb v3
else
CREATE_TABLE : = 'CREATE TABLE ' ;
2016-06-15 19:38:44 +00:00
if ATableName = ContactsTableName then begin
2016-06-14 21:43:21 +00:00
FConnection. ExecuteDirect(
2022-04-18 21:41:51 +00:00
CREATE_TABLE + 'Contacts (' +
2022-04-18 16:48:40 +00:00
'RecordID ' + FIDFieldTypeNameInSQL + ', ' +
'ResourceID INTEGER, ' +
2016-09-15 21:32:42 +00:00
'FirstName VARCHAR(50), ' +
'LastName VARCHAR(50), ' +
'Title VARCHAR(20) ,' +
'Category INTEGER, ' +
2016-06-14 21:43:21 +00:00
'Birthdate DATE, ' +
'Anniversary DATE, ' +
2016-09-16 23:42:31 +00:00
'Company VARCHAR(50), ' +
'Department VARCHAR(50), ' +
2016-06-14 21:43:21 +00:00
'Job_Position VARCHAR(30), ' +
2016-09-15 21:32:42 +00:00
'AddressType1 INTEGER, ' +
'Address1 VARCHAR(100), ' +
'City1 VARCHAR(50), ' +
'State1 VARCHAR(25), ' +
'Zip1 VARCHAR(10), ' +
'Country1 VARCHAR(25), ' +
'AddressType2 INTEGER, ' +
'Address2 VARCHAR(100), ' +
'City2 VARCHAR(50), ' +
'State2 VARCHAR(25), ' +
'Zip2 VARCHAR(10), ' +
'Country2 VARCHAR(25), ' +
2016-06-14 21:43:21 +00:00
'Notes VARCHAR(1024), ' +
2016-09-15 21:32:42 +00:00
'EMail1 VARCHAR(100), ' +
'EMail2 VARCHAR(100), ' +
'EMail3 VARCHAR(100), ' +
'EMailType1 INTEGER, ' +
'EMailType2 INTEGER, ' +
'EMailType3 INTEGER, ' +
2016-06-14 21:43:21 +00:00
'Phone1 VARCHAR(25), ' +
'Phone2 VARCHAR(25), ' +
'Phone3 VARCHAR(25), ' +
'Phone4 VARCHAR(25), ' +
'Phone5 VARCHAR(25), ' +
2016-06-15 10:54:33 +00:00
'PhoneType1 INTEGER, ' +
2016-06-14 21:43:21 +00:00
'PhoneType2 INTEGER, ' +
'PhoneType3 INTEGER, ' +
'PhoneType4 INTEGER, ' +
'PhoneType5 INTEGER, ' +
2016-09-15 21:32:42 +00:00
'Website1 VARCHAR(100), ' +
'Website2 VARCHAR(100), ' +
'WebsiteType1 INTEGER, ' +
'WebsiteType2 INTEGER, ' +
2016-06-14 21:43:21 +00:00
'Custom1 VARCHAR(100), ' +
'Custom2 VARCHAR(100),' +
'Custom3 VARCHAR(100), ' +
'Custom4 VARCHAR(100), ' +
'UserField0 VARCHAR(100), ' +
'UserField1 VARCHAR(100), ' +
'UserField2 VARCHAR(100), ' +
'UserField3 VARCHAR(100), ' +
'UserField4 VARCHAR(100), ' +
'UserField5 VARCHAR(100), ' +
'UserField6 VARCHAR(100), ' +
'UserField7 VARCHAR(100), ' +
'UserField8 VARCHAR(100), ' +
2016-06-15 19:38:44 +00:00
'UserField9 VARCHAR(100) )'
) ;
2016-09-19 20:57:45 +00:00
if CreateIndex then begin
FConnection. ExecuteDirect(
'CREATE INDEX ContactsResourceID_idx ON Contacts(ResourceID)'
) ;
FConnection. ExecuteDirect(
'CREATE INDEX ContactsName_idx ON Contacts(LastName, FirstName)'
) ;
FConnection. ExecuteDirect(
'CREATE INDEX ContactsCompany_idx ON Contacts(Company)'
) ;
end ;
2022-04-20 23:01:29 +00:00
if Lowercase( FConnection. Protocol) = 'firebird' then
CreateAutoInc_Firebird( 'Contacts' , 'RecordID' ) ;
2016-06-15 19:38:44 +00:00
end else
if ATableName = EventsTableName then begin
2016-06-14 21:43:21 +00:00
FConnection. ExecuteDirect(
2022-04-18 21:41:51 +00:00
CREATE_TABLE + 'Events (' +
2022-04-18 16:48:40 +00:00
'RecordID ' + FIdFieldTypeNameInSQL + ', ' +
2016-06-14 21:43:21 +00:00
'StartTime TIMESTAMP, ' +
'EndTime TIMESTAMP, ' +
'ResourceID INTEGER, ' +
'Description VARCHAR(255), ' +
'Location VARCHAR(255), ' +
'Notes VARCHAR(1024), ' +
'Category INTEGER, ' +
2022-04-18 16:48:40 +00:00
'AllDayEvent ' + FBoolFieldTypeNameInSQL + ', ' +
2016-06-14 21:43:21 +00:00
'DingPath VARCHAR(255), ' +
2022-04-18 16:48:40 +00:00
'AlarmSet ' + FBoolFieldTypeNameInSQL + ', ' +
2016-06-14 21:43:21 +00:00
'AlarmAdvance INTEGER, ' +
'AlarmAdvanceType INTEGER, ' +
'SnoozeTime TIMESTAMP, ' +
'RepeatCode INTEGER, ' +
'RepeatRangeEnd TIMESTAMP, ' +
'CustomInterval INTEGER, ' +
'UserField0 VARCHAR(100), ' +
'UserField1 VARCHAR(100), ' +
'UserField2 VARCHAR(100), ' +
'UserField3 VARCHAR(100), ' +
'UserField4 VARCHAR(100), ' +
'UserField5 VARCHAR(100), ' +
'UserField6 VARCHAR(100), ' +
'UserField7 VARCHAR(100), ' +
'UserField8 VARCHAR(100), ' +
2016-06-15 19:38:44 +00:00
'UserField9 VARCHAR(100) )'
) ;
2016-09-19 20:57:45 +00:00
if CreateIndex then begin
FConnection. ExecuteDirect(
'CREATE INDEX EventsResourceID_idx ON Events(ResourceID)'
) ;
FConnection. ExecuteDirect(
'CREATE INDEX EventsStartTime_idx ON Events(StartTime)'
) ;
FConnection. ExecuteDirect(
'CREATE INDEX EventsEndTime_idx ON Events(EndTime)'
) ;
end ;
2022-04-20 23:01:29 +00:00
if Lowercase( FConnection. Protocol) = 'firebird' then
CreateAutoInc_Firebird( 'Events' , 'RecordID' ) ;
2016-06-15 19:38:44 +00:00
end else
if ATableName = ResourceTableName then begin
2016-06-14 21:43:21 +00:00
FConnection. ExecuteDirect(
2022-04-18 21:41:51 +00:00
CREATE_TABLE + 'Resources ( ' +
2022-04-18 16:48:40 +00:00
'ResourceID ' + FIdFieldTypeNameInSQL + ', ' +
2016-06-14 21:43:21 +00:00
'Description VARCHAR(255), ' +
'Notes VARCHAR(1024), ' +
'ImageIndex INTEGER, ' +
2022-04-18 16:48:40 +00:00
'ResourceActive ' + FBoolFieldTypeNameInSQL + ', ' +
2016-06-14 21:43:21 +00:00
'UserField0 VARCHAR(100), ' +
'UserField1 VARCHAR(100), ' +
'UserField2 VARCHAR(100), ' +
'UserField3 VARCHAR(100), ' +
'UserField4 VARCHAR(100), ' +
'UserField5 VARCHAR(100), ' +
'UserField6 VARCHAR(100), ' +
'UserField7 VARCHAR(100), ' +
'UserField8 VARCHAR(100), ' +
2016-06-15 19:38:44 +00:00
'UserField9 VARCHAR(100) )'
) ;
2022-04-20 23:01:29 +00:00
if Lowercase( FConnection. Protocol) = 'firebird' then
CreateAutoInc_Firebird( 'Resources' , 'ResourceID' ) ;
2016-06-15 19:38:44 +00:00
end else
if ATableName = TasksTableName then begin
2016-06-14 21:43:21 +00:00
FConnection. ExecuteDirect(
2022-04-18 21:41:51 +00:00
CREATE_TABLE + 'Tasks (' +
2022-04-18 16:48:40 +00:00
'RecordID ' + FIdFieldTypeNameInSQL + ', ' +
2016-06-14 21:43:21 +00:00
'ResourceID INTEGER, ' +
2022-04-18 16:48:40 +00:00
'Complete ' + FBoolFieldTypeNameInSQL + ', ' +
2016-06-14 21:43:21 +00:00
'Description VARCHAR(255), ' +
'Details VARCHAR(1024), ' +
'CreatedOn TIMESTAMP, ' +
'Priority INTEGER, ' +
'Category INTEGER, ' +
'CompletedOn TIMESTAMP, ' +
'DueDate TIMESTAMP, ' +
'UserField0 VARCHAR(100), ' +
'UserField1 VARCHAR(100), ' +
'UserField2 VARCHAR(100), ' +
'UserField3 VARCHAR(100), ' +
'UserField4 VARCHAR(100), ' +
'UserField5 VARCHAR(100), ' +
'UserField6 VARCHAR(100), ' +
'UserField7 VARCHAR(100), ' +
'UserField8 VARCHAR(100), ' +
2016-06-15 19:38:44 +00:00
'UserField9 VARCHAR(100) )'
) ;
2016-09-19 20:57:45 +00:00
if CreateIndex then begin
FConnection. ExecuteDirect(
'CREATE INDEX TasksResourceID_idx ON Tasks(ResourceID)'
) ;
FConnection. ExecuteDirect(
'CREATE INDEX TasksDueDate_idx ON Tasks(DueDate)'
) ;
FConnection. ExecuteDirect(
'CREATE INDEX TasksCompletedOn_idx ON Tasks(CompletedOn)'
) ;
2022-04-20 23:01:29 +00:00
if Lowercase( FConnection. Protocol) = 'firebird' then
CreateAutoInc_Firebird( 'Tasks' , 'RecordID' ) ;
2016-09-19 20:57:45 +00:00
end ;
2016-06-15 19:38:44 +00:00
end ;
2016-06-14 21:43:21 +00:00
end ;
2016-06-17 20:23:56 +00:00
procedure TVpZeosDatastore. CreateTables;
var
wasConnected: Boolean ;
begin
2018-05-15 23:14:44 +00:00
if FConnection = nil then
raise EVpException. Create( 'Database must be connected in order to create tables.' ) ;
2016-06-17 20:23:56 +00:00
wasConnected : = FConnection. Connected;
2018-05-15 23:14:44 +00:00
try
// Make sure that Connection property has been set
if not wasConnected then
SetTableconnections( FConnection) ;
CreateAllTables;
finally
Connected : = wasConnected;
end ;
2016-06-17 20:23:56 +00:00
end ;
2016-09-19 20:57:45 +00:00
procedure TVpZeosDatastore. FixContactsTable;
var
list: TStrings;
autocommit: Boolean ;
fieldnames: TStrings;
begin
autocommit : = FConnection. AutoCommit;
ContactsTable. Close;
list : = TStringList. Create;
try
FConnection. GetColumnNames( ContactsTableName, '' , list) ;
FConnection. AutoCommit : = false ;
try
// Fields renamed in 1.05
fieldnames : = TStringList. Create;
try
if list. IndexOf( 'Address' ) > - 1 then fieldnames. Add( 'Address|Address1' ) ;
if list. IndexOf( 'City' ) > - 1 then fieldnames. Add( 'City|City1' ) ;
if list. IndexOf( 'State' ) > - 1 then fieldnames. Add( 'State|State1' ) ;
if list. IndexOf( 'Zip' ) > - 1 then fieldnames. Add( 'Zip|Zip1' ) ;
if list. IndexOf( 'Country' ) > - 1 then fieldnames. Add( 'Country|Country1' ) ;
if list. IndexOf( 'EMail' ) > - 1 then fieldnames. Add( 'EMail|EMail1' ) ;
if fieldnames. Count > 0 then begin
RenameFields( ContactsTableName, fieldnames) ;
exit; // This automatically creates the new fields
end ;
finally
fieldnames. Free;
end ;
// Fields added in 1.05
if list. IndexOf( 'Department' ) = - 1 then
AddField( ContactsTableName, 'Department' , ftString, 5 0 ) ;
if list. IndexOf( 'AddressType1' ) = - 1 then
AddField( ContactsTableName, 'AddressType1' , ftInteger) ;
if list. IndexOf( 'AddressType2' ) = - 1 then
AddField( ContactsTableName, 'AddressType2' , ftInteger) ;
if list. IndexOf( 'Address2' ) = - 1 then
AddField( ContactsTableName, 'Address2' , ftString, 1 0 0 ) ;
if list. IndexOf( 'City2' ) = - 1 then
AddField( ContactsTableName, 'City2' , ftString, 5 0 ) ;
if list. IndexOf( 'State2' ) = - 1 then
AddField( ContactsTableName, 'State2' , ftString, 2 5 ) ;
if list. IndexOf( 'Zip2' ) = - 1 then
AddField( ContactsTableName, 'Zip2' , ftString, 1 0 ) ;
if list. IndexOf( 'country2' ) = - 1 then
AddField( ContactsTableName, 'Country2' , ftString, 2 5 ) ;
if list. IndexOf( 'EMail2' ) = - 1 then
AddField( ContactsTableName, 'EMail2' , ftString, 1 0 0 ) ;
if list. IndexOf( 'EMail3' ) = - 1 then
AddField( ContactsTableName, 'EMail3' , ftString, 1 0 0 ) ;
if list. IndexOf( 'EMailType1' ) = - 1 then
AddField( ContactsTableName, 'EMailType1' , ftInteger) ;
if list. IndexOf( 'EMailType2' ) = - 1 then
AddField( ContactsTableName, 'EMailType2' , ftInteger) ;
if list. IndexOf( 'EMailType3' ) = - 1 then
AddField( ContactsTableName, 'EMailType3' , ftInteger) ;
if list. IndexOf( 'Website1' ) = - 1 then
AddField( ContactsTableName, 'Website1' , ftString, 1 0 0 ) ;
if list. IndexOf( 'Website2' ) = - 1 then
AddField( ContactsTableName, 'Website2' , ftString, 1 0 0 ) ;
if list. IndexOf( 'WebsiteType1' ) = - 1 then
AddField( ContactsTableName, 'WebsiteType1' , ftInteger) ;
if list. IndexOf( 'WebsiteType2' ) = - 1 then
AddField( ContactsTableName, 'WebsiteType2' , ftInteger) ;
FConnection. Commit;
except
FConnection. Rollback;
raise Exception. Create( 'Failure to update table structure to current VisualPlanIt version' ) ;
end ;
finally
list. Free;
end ;
FConnection. Connected : = false ;
FConnection. AutoCommit : = autocommit;
FConnection. Connected : = true ;
end ;
2016-06-14 21:43:21 +00:00
function TVpZeosDatastore. GetContactsTable: TDataset;
begin
Result : = FContactsTable;
end ;
function TVpZeosDatastore. GetEventsTable: TDataset;
begin
Result : = FEventsTable;
end ;
2022-04-18 16:48:40 +00:00
{ This is not needed in the ZEOS datastore as these tables use
autoincrement fields. }
function TVpZeosDatastore. GetNextID( TableName: string ) : integer ;
2016-06-14 21:43:21 +00:00
begin
2022-04-20 23:01:29 +00:00
Result : = - 1 ;
2016-06-14 21:43:21 +00:00
end ;
function TVpZeosDatastore. GetResourceTable : TDataset;
begin
Result : = FResourceTable;
end ;
function TVpZeosDatastore. GetTasksTable : TDataset;
begin
Result : = FTasksTable;
end ;
2023-10-10 22:24:46 +00:00
{ Removes all contacts of the specified resource from the database. }
procedure TVpZeosDataStore. InternalPurgeContacts( Res: TVpResource) ;
var
sql: String ;
begin
sql : = Format( 'DELETE FROM Contacts WHERE ResourceID = %d' , [ Res. ResourceID] ) ;
FConnection. ExecuteDirect( sql) ;
end ;
{ Removes all events of the specified resource from the database. }
procedure TVpZeosDatastore. InternalPurgeEvents( Res: TVpResource) ;
var
sql: String ;
begin
sql : = Format( 'DELETE FROM Events WHERE ResourceID = %d' , [ Res. ResourceID] ) ;
FConnection. ExecuteDirect( sql) ;
end ;
{ Removes all tasks of the specified resource from the database. }
procedure TVpZeosDatastore. InternalPurgeTasks( Res: TVpResource) ;
var
sql: String ;
begin
sql : = Format( 'DELETE FROM Tasks WHERE ResourceID = %d' , [ Res. ResourceID] ) ;
FConnection. ExecuteDirect( sql) ;
end ;
2016-06-14 21:43:21 +00:00
procedure TVpZeosDatastore. Loaded;
begin
inherited ;
if not ( csDesigning in ComponentState) then
2016-06-17 20:23:56 +00:00
Connected : = AutoConnect and (
AutoCreate or
( FContactsTable. Exists and FEventsTable. Exists and FResourceTable. Exists and FTasksTable. Exists)
) ;
2016-06-14 21:43:21 +00:00
end ;
2016-06-15 09:42:30 +00:00
procedure TVpZeosDatastore. Notification( AComponent: TComponent;
Operation: TOperation) ;
begin
inherited Notification( AComponent, Operation) ;
if ( Operation = opRemove) and ( AComponent = FConnection) then
FConnection : = nil ;
end ;
2016-09-19 20:57:45 +00:00
{ Renames the fields specified in the list. Each list item contains old and new
fieldnames separated by a bar character ( | ) .
Note that sqlite3 does not provide a command for renaming of fields. Therefore,
the old table is renamed to a temp table, a new table with the renamed fields
is created and the content of the temp table is copied to the new table.
Finally the temp table is deleted.
See:
https: //stackoverflow.com/questions/805363/how-do-i-rename-a-column-in-a-sqlite-database-table
TO DO :
Take care of the case that a renamed field belongs to an index , constraint, etc.
( this case is ignored currently) . }
procedure TVpZeosDatastore. RenameFields( ATableName: String ; AFields: TStrings) ;
const
NO_INDEX = false ;
var
sql: String ;
oldFields: TStrings;
oldfn, newfn: String ;
srcfn, destfn: String ;
i, j, p: Integer ;
done: Boolean ;
begin
oldfields : = TStringList. Create;
try
FConnection. GetColumnNames( ATableName, '' , oldfields) ;
{ 1 - Rename old table (append _TMP to tablename) }
sql : = Format( 'ALTER TABLE %0:s RENAME TO %0:s_TMP;' , [ ATableName] ) ;
FConnection. ExecuteDirect( sql) ;
{ 2 - Create new table }
if ATableName = ContactsTableName then
CreateTable( ContactsTableName, NO_INDEX) else
if ATablename = EventsTableName then
CreateTable( EventsTablename, NO_INDEX) else
if ATableName = ResourceTableName then
CreateTable( ResourceTableName, NO_INDEX) else
if ATableName = TasksTableName then
CreateTable( TasksTableName, NO_INDEX)
else
raise Exception. Create( 'Unknown table in RenameFields.' ) ;
{ 3 - Copy contents from temp table to new table }
srcfn : = '' ;
destfn : = '' ;
for i: = 0 to oldfields. Count- 1 do begin
done : = false ;
// Is field "oldfields[i]" contained in the list of fields to be renamed?
for j: = 0 to AFields. Count- 1 do begin
p : = pos( '|' , AFields[ j] ) ;
oldfn : = copy( AFields[ j] , 1 , p- 1 ) ;
newfn : = copy( AFields[ j] , p+ 1 , MaxInt) ;
if oldfn = oldfields[ i] then begin
// yes: add old field name to srcfn, new field name to destfn
srcfn : = srcfn + ',' + oldfn;
destfn : = destfn + ',' + newfn;
done : = true ;
break;
end ;
end ;
if not done then begin
// no: add current field name to srcfn and destfn
srcfn : = srcfn + ',' + oldfields[ i] ;
destfn : = destfn + ',' + oldfields[ i] ;
end ;
end ;
// Remove the beginning comma added above.
if srcfn < > '' then System. Delete( srcfn, 1 , 1 ) ;
if destfn < > '' then System. Delete( destfn, 1 , 1 ) ;
// Execute INSERT command
sql : = Format(
'INSERT INTO %0:s (%1:s) SELECT %2:s FROM %0:s_TMP;' , [
ATableName, destfn, srcfn
] ) ;
FConnection. ExecuteDirect( sql) ;
{ 4 - Finally delete the temp table }
sql : = Format( 'DROP TABLE %s_TMP;' , [ ATableName] ) ;
FConnection. ExecuteDirect( sql) ;
FConnection. Disconnect;
FConnection. Connect;
finally
oldfields. Free;
end ;
end ;
2016-06-14 21:43:21 +00:00
procedure TVpZeosDatastore. SetConnected( const AValue: Boolean ) ;
2018-05-15 23:14:44 +00:00
var
canLoad: Boolean = false ;
2016-06-14 21:43:21 +00:00
begin
2016-06-17 21:29:44 +00:00
if ( AValue = Connected) or ( FConnection = nil ) then
2016-06-14 21:43:21 +00:00
exit;
2018-05-15 23:14:44 +00:00
if AValue and AutoCreate and not TablesExist then
2016-06-14 21:43:21 +00:00
CreateTables;
FConnection. Connected : = AValue;
2018-05-15 23:14:44 +00:00
if FConnection. Connected and TablesExist then begin
2016-06-14 21:43:21 +00:00
FContactsTable. Open;
2022-05-23 11:14:19 +00:00
// If field "Department" does not exist then it is an old table and must be reworked.
if ContactsTable. Fields. FindField( 'Department' ) = nil then
begin
FixContactsTable;
FContactsTable. Open;
end ;
2016-06-14 21:43:21 +00:00
FEventsTable. Open;
FResourceTable. Open;
FTasksTable. Open;
2018-05-15 23:14:44 +00:00
canLoad : = true ;
2016-06-14 21:43:21 +00:00
end ;
inherited SetConnected( AValue) ;
2018-05-15 23:14:44 +00:00
if canLoad then
2016-06-15 09:42:30 +00:00
Load;
2016-06-14 21:43:21 +00:00
end ;
2016-06-15 09:42:30 +00:00
procedure TVpZeosDatastore. SetConnection( const AValue: TZConnection) ;
var
wasConnected: Boolean ;
2016-06-14 21:43:21 +00:00
begin
2016-06-15 09:42:30 +00:00
if AValue = FConnection then
exit;
2016-06-14 21:43:21 +00:00
2018-05-15 23:14:44 +00:00
wasConnected : = ( AValue < > nil ) and AValue. Connected and
( FConnection < > nil ) and FConnection. Connected;
2016-06-15 09:42:30 +00:00
FConnection : = AValue;
2022-04-18 16:48:40 +00:00
AdjustSQLFieldTypeNames;
2018-05-15 23:14:44 +00:00
if not Connected then
SetTableConnections( FConnection) ;
if AutoCreate and ( FConnection < > nil ) then
CreateTables;
if Autoconnect or wasConnected then
Connected : = true ;
end ;
// Must be disconnected!
procedure TVpZeosDatastore. SetTableConnections( AConnection: TZConnection) ;
begin
if FContactsTable. Connection = nil then begin
FContactsTable. Connection : = AConnection;
FEventsTable. Connection : = AConnection;
FResourcetable. Connection : = AConnection;
FTaskstable. Connection : = AConnection;
end ;
end ;
2022-06-08 11:09:59 +00:00
function TVpZeosDatastore. TableExists( ATableName: String ) : Boolean ;
var
L: TStringList;
begin
Result : = false ;
if not FConnection. Connected then
exit;
L : = TStringList. Create;
try
L. CaseSensitive : = false ;
FConnection. GetTableNames( '' , L) ;
Result : = L. IndexOf( ATablename) < > - 1 ; ;
finally
L. Free;
end ;
end ;
2018-05-15 23:14:44 +00:00
function TVpZeosDatastore. TablesExist: Boolean ;
var
L: TStringList;
begin
Result : = false ;
if not FConnection. Connected then
exit;
L : = TStringList. Create;
try
L. CaseSensitive : = false ;
FConnection. GetTableNames( '' , L) ;
Result : = ( L. IndexOf( FContactsTable. TableName) < > - 1 ) and
( L. IndexOf( FEventsTable. TableName) < > - 1 ) and
( L. IndexOf( FResourceTable. TableName) < > - 1 ) and
( L. IndexOf( FTasksTable. TableName) < > - 1 ) ;
finally
L. Free;
end ;
2016-06-14 21:43:21 +00:00
end ;
end .