The databases are created at run-time. The thread should be run every 15 minutes to query for new records in a given database. I've gotten it the point where the Thread seems to be working, but the TFDConnection keeps throwing a:
Thread: [FireDAC][Comp][Clnt]-512. Connection is not defined for []. Possible reason: Connection and ConnectionName property values are both empty
I tried to follow the Delphi example for Pooling, but Delphi doesn't exactly port well to C++. So I did it the best way I know. Here's are two code snippets for the Thread and the calling method.
__fastcall TDataHandlerThread::TDataHandlerThread(bool CreateSuspended, TFDPhysDriverLink *ADriverLink,
TDataSource *DataSource, String AConnectionStr,
String ACommandStr) : TThread(false)
{
FreeOnTerminate = true;
try {
std::unique_ptr<TFDConnection> FConnection = std::make_unique<TFDConnection>(nullptr);
std::unique_ptr<TFDEventAlerter> FAlerter = std::make_unique<TFDEventAlerter>(nullptr);
FQuery = std::make_unique<TFDQuery>(nullptr);
FDataSource = DataSource;
TFDPhysDriverLink *DriverLink = ADriverLink;
FAlerter->OnAlert = PgEventAlerterAlert;
FAlerter->Options->Kind = "Notifies";
FAlerter->Options->Synchronize = True;
FAlerter->Options->Timeout = 10000;
FAlerter->OnAlert = PgEventAlerterAlert;
FAlerter->Active = True;
FAlerter->Register();
FConnection->ConnectionString = AConnectionStr; // Prvate Connection String;
FConnection->ConnectionName="PG";
FConnection->Connected = true;
FQuery->Connection = FConnection.get();
FQuery->SQL->Text = ACommandStr;
FDataSource->DataSet = FQuery.get();
} catch (const Exception &exception) {
AlertMainForm("Exception in Thread: " + exception.Message);
Terminate();
}
}
//---------------------------------------------------------------------------
void __fastcall TDataHandlerThread::AlertMainForm(String str)
{
TThread::Queue(NULL, [this, str]() -> void {
MainForm->Memo->Lines->Add("THREAD: " + str);
});
}
TDataHandlerThread::~TDataHandlerThread()
{
}
//---------------------------------------------------------------------------
void __fastcall TDataHandlerThread::Execute()
{
try
{
// while(!Terminated)
if(!Terminated)
{
if(FQuery->Active) {
FQuery->Close();
FDataSource->Enabled=false;
}
FQuery->Open();
FDataSource->Enabled=true;
std::this_thread::sleep_for(std::chrono::minutes(5));
}
}
catch(const Exception &exception)
{
AlertMainForm("THREAD: ERROR " + exception.Message);
}
}
And from the calling method:
void __fastcall TScheduler::DoExecute()
{
try
{
String Pg_Connect_str = "DriverID=PG;Server=XX.XXX.XX.XXX;Port=XXXXX;Database=XXXXX;User_Name=XXXXXX; \
Password=----;CharacterSet=utf8;ExtendedMetadata=true;";
String CmdStr = "select * from customers WHERE last_update_time > " + FormatDateTime( "yyyy-mm-dd hh:mm:ss", FLastRetrievalTime ) + "'");;
TDataHandlerThread *runner = new TDataHandlerThread(false, FDPhysPgDriverLink, dsJwareCustomers, Pg_Connect_str, CmdStr);
} catch (const Exception &exception) {
MainForm->ExceptionThrown("Exc:[0x0A][Execute]:" + exception.Message );
}
}
In the past, I've been able to drop a TFDConnection onto a DataModule for use with Postgres and set it up entirely in code, not assigning a ConnectionName nor a Driver, yet using the same technique here it is not getting the connection.
You are creating and destroying the
TFDConnectionobject (and theTFDEventAlerterobject) in your thread's constructor using localunique_ptrvariables that go out of scope when the constructor exits.Thus, the
TFDConnectionobject won't exist anymore when the thread callsExecute(), so theTFDQueryobject can't do its work. You can verify this by looking at theFQuery->Connectionproperty inside ofExecute()- it will have been reset back to null when theTFDConnectionobject is destroyed.If you are going to create the objects in the thread's constructor, you need to get rid of the local
unique_ptrvariables. Make them members of the thread class instead, as you appear to have done for theTFDQueryobject.Otherwise, create all objects locally in
Execute()instead.