Page 1 of 1

Unidac and FR4 ADO do not get along.

Posted: Thu 21 Jul 2011 06:16
by kamiller42
Yes, I know you can use Unidac in FR4, but I have some reports using ADO. When the application loads the report file, it setup the ADO dataset in the report. This is when Unidac starts to break down. What happens is the Unidac datasets are closed and the Unidac connection component unassigned from all Unidac datasets.

I don't have Uni's source, so this call stack is based on VCL debug DCUs.

Code: Select all

DB.TDataSet.SetActive(???)
:006874b2 TCustomDADataSet.SetActive + $42
ADODB.TADOCommand.AssignCommandText('select M.Doni_Num'#$D#$A',M.Assignor_Num'#$D#$A',D.Document_Title'#$D#$A',D.Internal_Title'#$D#$A',D.Document_Category'#$D#$A',D.Document_ID'#$D#$A'from Master M'#$D#$A'inner join Document D on D.Document_Domain_Cd=M.Document_Domain_Cd'#$D#$A'inner join Master_Document MD on M.Master_ID=MD.Master_ID and MD.Document_ID=D.Document_ID'#$D#$A'where exists (select 1 from Master_Document_Activity MDA '#$D#$A'              where MDA.Master_Document_Id=Md.Master_Document_ID'#$D#$A'              and MDA.Document_Activity_Cd='DOCREQSENT')'#$D#$A'and not exists (select 1 from Master_Document_Activity MDA '#$D#$A'                where MDA.Master_Document_Id=Md.Master_Document_ID'#$D#$A'                and MDA.Document_Activity_Cd='DOCREQREC')'#$D#$A'order by D.Internal_Title, M.Doni_Num                                                                                                                          '#$D#$A,False)
ADODB.TADOCommand.SetCommandText(???)
ADODB.TCustomADODataSet.SetCommandText(???)
ADODB.TADOQuery.QueryChanged(???)
WideStrings.TWideStringList.Changed
WideStrings.TWideStringList.SetUpdateState(???)
WideStrings.TWideStrings.EndUpdate
WideStrings.TWideStrings.Assign(???)
frxADOComponents.TfrxADOQuery.OnChangeSQL($1347DA0)
Classes.TStringList.Changed
Classes.TStringList.SetUpdateState(???)
Classes.TStrings.EndUpdate
Classes.TStrings.SetTextStr(???)
frxXMLSerializer.TfrxXMLSerializer.XMLToObj('Name="dstReport" UserName="dstReport" CloseDataSource="True" FieldAliases.Text="" BCDToCurrency="False" IgnoreDupParams="False" SQL.Text="select M.Doni_Num
,M.Assignor_Num
,D.Document_Title
,D.Internal_Title
,D.Document_Category
,D.Document_ID
from Master M
inner join Document D on D.Document_Domain_Cd=M.Document_Domain_Cd
inner join Master_Document MD on M.Master_ID=MD.Master_ID and MD.Document_ID=D.Document_ID
where exists (select 1 from Master_Document_Activity MDA 
              where MDA.Master_Document_Id=Md.Master_Document_ID
              and MDA.Document_Activity_Cd='DOCREQSENT')
and not exists (select 1 from Master_Document_Activity MDA 
                where MDA.Master_Document_Id=Md.Master_Document_ID
                and MDA.Document_Activity_Cd='DOCREQREC')
order by D.Internal_Title, M.Doni_Num                                                                                                                          " CommandTimeout="30" Database="conReport" LockType="ltReadOnly" PropData="05704C65667402300470546F7002500A506172616D65746572730100"',$10BC1A0)
TCustomAdoDataSet.AssignCommandText, this is the beginning of the end of Unidac's connection. It's when the following line of code is called that Unidac starts to shutdown the datasets...

Code: Select all

    OLEDBCommand := (Command.CommandObject as ADOCommandConstruction).OLEDBCommand as ICommand;
That line of code is from AdoDb.pas, TParameters.InternalFresh.RefreshFromOleDb.

Is there a way to get Unidac and Ado to work together in the same application?

Posted: Thu 21 Jul 2011 10:45
by AndreyZ
Hello,

I cannot reproduce the problem. Please try composing a small sample to demonstrate the problem and send it to andreyz*devart*com, including a script to create server objects. Also please specify the following:
- the exact version of UniDAC. You can learn it from the About sheet of TUniConnection Editor;
- the exact version of your IDE.

Posted: Thu 21 Jul 2011 20:13
by kamiller42
Andrey, after examining several stacks and even the CPU debugger window, I figured it out. The problem... it's a doozy and a really strange one.

When the report is loaded and the XML turned into an object, the first ado query in the report was instantly being assigned a connection component. Since it's a TAdoQuery, you would think the connection component would be the one in the report of type TAdoConnection. No, it was being assigned a TUniConnection.

How can you attach a TUniConnection to an ADO component?? Ado Components require a TAdoConnection! This is how it happened.

This application was an ADO application converted using the Unidac conversion wizard. After some tweaking here and there, it was up and running. However, the frxAdoComponents component on the reports datamodule still had its DefaultDatabase property pointing to conMain on the main datamodule. That is technically forbidden because the property will only accept TAdoConnections, but it was in the DFM nonetheless.

When the report is loaded, FR finds an object with that name and latches it onto the report's ADO query component. No type checking performed anywhere in this process. The formula for meltdown had been set. Evaluating TAdoQuery(MyReportAdoQuery).Connection.ClassName returned TUniConnection. Ouch!

So, this appears to be a conversion mishap along with FR (or VCL ADO code?) performing too much pointer passing without adequate type checking somewhere along the way. Solution, unassign frxAdoComponents1.DefaultDatabase. Next step is to try going Unidac in FR.

Posted: Fri 22 Jul 2011 08:18
by AndreyZ
Migration Wizard serves only to simplify routine operations. It means that after migration you will still need to make corrections to your project. In this case, you should use FastReport UniDAC components. To use FastReport UniDAC Components, you should compile and install them manually using IDE. You can learn how to do this in the %UniDAC_Install_Directory%\Demos\ThirdParty\FastReport\FR4\readme.txt file.