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 TFDConnection
object (and the TFDEventAlerter
object) in your thread's constructor using local unique_ptr
variables that go out of scope when the constructor exits.
Thus, the TFDConnection
object won't exist anymore when the thread calls Execute()
, so the TFDQuery
object can't do its work. You can verify this by looking at the FQuery->Connection
property inside of Execute()
- it will have been reset back to null when the TFDConnection
object is destroyed.
If you are going to create the objects in the thread's constructor, you need to get rid of the local unique_ptr
variables. Make them members of the thread class instead, as you appear to have done for the TFDQuery
object.
Otherwise, create all objects locally in Execute()
instead.