I wrote about this back in November of 2020 in this post, so be sure to read that post for for all the background information. Today I found yet another way this managed to introduce bugs into your application. Read on for the details
This time all the code for my report is done in the report, so I should be safe right? WRONG!!! In this instance I am passing in the ID of the parent record for the report to use. Nothing fancy just
PROCEDURE rptSampleProcessingPooled(LOCAL SampleProcessingID)
Well guess what … When you then try to export the report to PDF (or any of the other export options) of the print preview the report is reran, as we established in the previous article. The problem is that when it is reran I mean the either report include the Opening rptxxxxxx code (what would be the global section on a window), and when it does the passed in variable is not empty!!! You heard me it zeroed out my passed in variable.
You might be thinking that it has something to do with my LOCAL keyword, which by the way is there to make sure that the variable used to call the report doesn’t accidently get changed by code in the report since by default variables are passed by address. Sadly I tested without the LOCAL keyword and had the same issue.
You can see this for yourself by placing a Debug Break after the procedure declaration of your report and you will notice when you try to export to PDF from the preview that your break will fire for a second time.
The fix for this is kind of ugly, at least to me. Any of my mentoring clients can probably tell you a story of me preaching about the use of global variables, especially for passing parameters. But in this case I had to create a global variable (Glo.inSampleProcessingID) to hold the value so it wouldn’t get reinitialized on the export.
I tried using it as a default value like so
PROCEDURE rptSampleProcessingPooled(LOCAL SampleProcessingID is int = Glo.inSampleProcessingID )
Glo.inSampleProcessingID = SampleProcessingID
I was hoping that since the Global gets set the first time the report runs, it would then use that value as the default for the second pass. But it appears that when the report is reran from the export, it actually passes the 0 value so my default didn’t get used. So this is what I ended up with as my final solution
PROCEDURE rptSampleProcessingPooled(LOCAL SampleProcessingID)
IF SampleProcessingID = 0 THEN
SampleProcessingID = Glo.inSampleProcessingID
ELSE
Glo.inSampleProcessingID = SampleProcessingID
END
In the first pass SampleProcessingID will have a value, so it will fall to the ELSE and set the Global, during the rerun fired by the export, SampleProcessingID doesn’t have a value, so it gets set to the value stored in the global from the original running of the report.
I really wish PCSOFT would reconsider how the export functions work from the print preview, or at the very least, figure out how to recall the report with any parameters that were passed in!
Update Jan 28, 2021
The good news is PCSOFT is listening and watching. They asked me for a sample project demonstrating this issue. While creating that sample project I discovered the issue is a bit more complicated than I first believed. It only happens when you pass a file variable to the report. And then inside the report load a different record from that same file. I won’t go into all the details of my database design but this was a Lot record and sometimes, it refers back to another Lot record (original lot), and the report would get the original lot to print some of that info as well. The way it was coded if there wasn’t an original lot, the ID was being cleared, which is where I was getting a 0 on the export.
So it appear that it is a bug with the Local keyword on the report. Here is some code bits to help you understand it, the below code calls the report:
TestData.TestDataID = 5
iPrintReport(rptReport,TestData.TestDataID)
The Report has code like this:
PROCEDURE MyReport(LOCAL inValue)
HReadSeekFirst(TestData,TestDataID,inValue)
iPrintBlock(blkTest)
ID is int = inValue +1
HReadSeekFirst(TestData,TestDataID,ID)
iPrintBlock(blkTest)
So its fetches and prints the block passed in, and then fetches the next record (ID = 6 in the example) and prints it as well. When you then choose Export to PDF from the print preview and the report reruns, inValue is now the value of the second record (6) instead of the original value of (5). Since inValue is defined as Local it should not have any relationship to TestData.TestDataID and changing one should not effect the other, but obviously does. FYI the report is also set to Independent HF context, incase you were wondering if that would make a difference.
So now that we have isolated it to a specific bug hopefully we will get a fix, but the good news is at least now I understand how to code around it in a clear way.
Instead of calling the report with File variables, always use local variables, If we change the report code to the following code it works as it should
TestData.TestDataID = 5
ID is int = TestData.TestDataID
iPrintReport(rptReport,ID)
Update Feb 1, 2021
PCSOFT has confirmed that this an issue with the independent context of HF in reports and a fix is planned for the next update.