Re: [harbour-users] Digest for harbour-users@googlegroups.com - 11 updates in 3 topics

58 views
Skip to first unread message

A Santos

unread,
Mar 24, 2026, 3:53:18 PM (2 days ago) Mar 24
to harbou...@googlegroups.com
Hi all!

Harbour offers the possibility of creating dbf and index files in memory. Handling them is done same way like hard drive ones.

See example in contrib/hbmemio/tests

Best regards. 

Em seg., 23 de mar. de 2026 12:48, <harbou...@googlegroups.com> escreveu:
Francesco Perillo <fper...@gmail.com>: Mar 22 05:41PM +0100

Yes, of course. Perhaps HASH but I don't know how they are implemented
internally.
But you are right, there should be a way for a better ram storage:
- one possibility is to create a new algorithm, in C of course, to create a
sort of index, like a....
- NTX/CDX index... so it may be interesting to copy the 3 files in ram and
create the indexes.
 
We lack important informations...
 
Il Sab 21 Mar 2026, 23:20 'Nenad Batoćanin' via Harbour Users <
Nenad Batoćanin <nbato...@wings.rs>: Mar 23 12:17AM +0100

If anyone remembers the CA Visual Objects project... It had a very nice object-oriented approach to working with the database. It looks like this:
 

 
oDb := DBServer ("Test")
 
oDb:SetIndex ("Test_ID")
 
WHILE ! oDb:Eof()
 
IF oDb:Id == 0
 
oDb:Id := RecNo()
 
oDb:Name := "None"
 
END IF
 
oDb:Skip()
 
END DO
 

 
I believe this code is clear to everyone :) The really good thing is that almost identical code could also work with SQL Server. Only the initialization was a little different:
 

 
oDb := SQLSelect ("SELECT * FROM Test ORDER BY Id")
 

 
Regards, NB
 

 

 
From: harbou...@googlegroups.com <harbou...@googlegroups.com> On Behalf Of Francesco Perillo
Sent: nedelja, 22. mart 2026. 17:41
To: harbou...@googlegroups.com
Subject: Re: [harbour-users] Refactoring legacy code to OOP — class/object access 5–7× slower than array
 

 
Yes, of course. Perhaps HASH but I don't know how they are implemented internally.
 
But you are right, there should be a way for a better ram storage:
 
- one possibility is to create a new algorithm, in C of course, to create a sort of index, like a....
 
- NTX/CDX index... so it may be interesting to copy the 3 files in ram and create the indexes.
 

 
We lack important informations...
 

 
Il Sab 21 Mar 2026, 23:20 'Nenad Batoćanin' via Harbour Users <harbou...@googlegroups.com <mailto:harbour-users@googlegroups.com> > ha scritto:
 
Hi!
 
I think AScan does a simple sequential search, so it can't be as fast as index search. Perhaps a replacement for AScan could be made that uses a memory table and a seek search?
 

 
Regards, NB
 

 
From: harbou...@googlegroups.com <mailto:harbour-users@googlegroups.com> <harbou...@googlegroups.com <mailto:harbour-users@googlegroups.com> > On Behalf Of Francesco Perillo
Sent: subota, 21. mart 2026. 21:58
To: harbou...@googlegroups.com <mailto:harbour-users@googlegroups.com>
Subject: Re: [harbour-users] Refactoring legacy code to OOP — class/object access 5–7× slower than array
 

 
I was having a second look at your code and I still think that using objects is not the way to go.
 

 
Also, you are not providing informations on the relationships of the records, one-to-one, one-to-many, many-to-many... the code seems to be a one-to-one
 

 
Without more informations it is difficult to give some clues, but I ask you, out of curiosity, to change the code in this way and report if there is a speed improvement
 
The new code explicitely uses local variables in the aScan codeblock; I don't know if Harbour optimizes oHdr:code+oHdr:key
 

 
LOCAL cKH, cKD
 
FOR EACH oHdr IN aHeader // ~1,000 records
 
cKH := oHdr:code + oHdr:key
 
nn := AScan(aDetails, {|x| x:code+x:key = cKH }) // ~3,000 records total
IF nn > 0
oDtl := aDetails[nn]
 
cKD := oDtl:code + oDtl:key
 
kk := AScan(aSubs, {|x| x:code+x:key = cKD }) // ~5,000 records total
IF kk > 0
oDtl := aSubs[kk]
// read properties, compute, output
ENDIF
ENDIF
NEXT
 

 

 

 
FOR EACH oHdr IN aHeader // ~1,000 records
nn := AScan(aDetails, {|x| x:code+x:key = oHdr:code+oHdr:key }) // ~3,000 records total
IF nn > 0
oDtl := aDetails[nn]
kk := AScan(aSubs, {|x| x:code+x:key = oDtl:code+oDtl:key }) // ~5,000 records total
IF kk > 0
oDtl := aSubs[kk]
// read properties, compute, output
ENDIF
ENDIF
NEXT
 
Any guidance from those who have done similar legacy refactoring
projects would be greatly appreciated.
 
Thank you,
Atul Parate
 
--
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com <mailto:harbour-users%2Bunsubscribe@googlegroups.com>
Web: https://groups.google.com/group/harbour-users
---
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to harbour-user...@googlegroups.com <mailto:harbour-users+unsubscribe@googlegroups.com> .
To view this discussion visit https://groups.google.com/d/msgid/harbour-users/947f4824-e06d-4d4e-aa9c-5ff689cb99f0n%40googlegroups.com <https://groups.google.com/d/msgid/harbour-users/947f4824-e06d-4d4e-aa9c-5ff689cb99f0n%40googlegroups.com?utm_medium=email&utm_source=footer> .
 
--
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com <mailto:harbour-users+unsubscribe@googlegroups.com>
Web: https://groups.google.com/group/harbour-users
---
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to harbour-user...@googlegroups.com <mailto:harbour-users+unsubscribe@googlegroups.com> .
To view this discussion visit https://groups.google.com/d/msgid/harbour-users/CADPHLr9RmwyV7Gca1zGtUyudF0JCNuM%3DW04EvP2VvEX7Errwsw%40mail.gmail.com <https://groups.google.com/d/msgid/harbour-users/CADPHLr9RmwyV7Gca1zGtUyudF0JCNuM%3DW04EvP2VvEX7Errwsw%40mail.gmail.com?utm_medium=email&utm_source=footer> .
 
--
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com <mailto:harbour-users%2Bunsubscribe@googlegroups.com>
Web: https://groups.google.com/group/harbour-users
---
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to harbour-user...@googlegroups.com <mailto:harbour-users+unsubscribe@googlegroups.com> .
To view this discussion visit https://groups.google.com/d/msgid/harbour-users/008601dcb980%24ecd55a70%24c6800f50%24%40wings.rs <https://groups.google.com/d/msgid/harbour-users/008601dcb980%24ecd55a70%24c6800f50%24%40wings.rs?utm_medium=email&utm_source=footer> .
 
--
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com <mailto:harbour-users+unsubscribe@googlegroups.com>
Web: https://groups.google.com/group/harbour-users
---
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to harbour-user...@googlegroups.com <mailto:harbour-users+unsubscribe@googlegroups.com> .
To view this discussion visit https://groups.google.com/d/msgid/harbour-users/CADPHLr-OJcJniJq7XKDmy%3D7xfdW_GxBGP4JoYLa9WXG0co32PQ%40mail.gmail.com <https://groups.google.com/d/msgid/harbour-users/CADPHLr-OJcJniJq7XKDmy%3D7xfdW_GxBGP4JoYLa9WXG0co32PQ%40mail.gmail.com?utm_medium=email&utm_source=footer> .
Mario H. Sabado <mhsa...@gmail.com>: Mar 23 01:30PM +0800

Hi Atul,
 
Not an OOP sample but I have come up with this approach when I have a need
to export a DBF file with over ~21M records to CSV. I need to process each
line as an array because of some necessary data conversion before saving to
the final CSV. I also tried the FOR/While combination approach but it's
over 10X slower than AEval() in my case scenario.
 
Below is my code snippet based on my understanding of your case.
 
Best regards,
Mario
 
*************************
function MasterDetailSubs
*************************
local xVal,yVal
 
local aHeader:={{"H1","H1 Header"},;
{"H2","H2 Header"},;
{"H3","H3 Header"} }
 
local aDetails:={{"H1","H1-Detail 1"},;
{"H1","H1-Detail 2"},;
{"H1","H1-Detail 3"},;
;
{"H2","H2-Detail 1"},;
{"H2","H2-Detail 2"},;
{"H2","H2-Detail 3"},;
;
{"H3","H3-Detail 1"},;
{"H3","H3-Detail 2"},;
{"H3","H3-Detail 3"} }
 
local aSubs :={ {"H1","H1-Detail 1","H1 D1 Sub 1"},;
{"H1","H1-Detail 1","H1 D1 Sub 2"},;
;
{"H1","H1-Detail 2","H1 D2 Sub 1"},;
{"H1","H1-Detail 2","H1 D2 Sub 2"},;
;
{"H1","H1-Detail 3","H1 D3 Sub 1"},;
{"H1","H1-Detail 3","H1 D3 Sub 2"},;
;
{"H2","H2-Detail 1","H2 D1 Sub 1"},;
{"H2","H2-Detail 1","H2 D1 Sub 2"},;
;
{"H2","H2-Detail 2","H2 D2 Sub 1"},;
{"H2","H2-Detail 2","H2 D2 Sub 2"},;
;
{"H2","H2-Detail 3","H2 D3 Sub 1"},;
{"H2","H2-Detail 3","H2 D3 Sub 2"},;
;
{"H3","H3-Detail 1","H3 D1 Sub 1"},;
{"H3","H3-Detail 1","H3 D1 Sub 2"},;
;
{"H3","H3-Detail 2","H3 D2 Sub 1"},;
{"H3","H3-Detail 2","H3 D2 Sub 2"},;
;
{"H3","H3-Detail 3","H3 D3 Sub 1"},;
{"H3","H3-Detail 3","H3 D3 Sub 2"} }
 
AEval(aHeader,{|x|Qout( (xVal:=x[1])+"-"+x[2] ), ; //Header
,AEval(aDetails,{|y| iif(xVal==y[1],Qout(yVal:=y[1]+y[2]), ) ;
//Detail
, AEval(aSubs,{|z| iif(xVal==z[1] .and.
yVal==z[1]+z[2], Qout( yVal+"-"+z[3]) , ) ; //Sub-Detail
}) ;
}) ;
})
return nil
 
/* SAMPLE OUTPUT
H1-Header 1
H1H1-Detail 1
H1H1-Detail 1-H1 D1 Sub 1
H1H1-Detail 1-H1 D1 Sub 2
H1H1-Detail 2
H1H1-Detail 2-H1 D2 Sub 1
H1H1-Detail 2-H1 D2 Sub 2
H1H1-Detail 3
H1H1-Detail 3-H1 D3 Sub 1
H1H1-Detail 3-H1 D3 Sub 2
H1H1-Detail 3-H1 D3 Sub 1
H1H1-Detail 3-H1 D3 Sub 2
H1H1-Detail 3-H1 D3 Sub 1
H1H1-Detail 3-H1 D3 Sub 2
H1H1-Detail 3-H1 D3 Sub 1
H1H1-Detail 3-H1 D3 Sub 2
H1H1-Detail 3-H1 D3 Sub 1
H1H1-Detail 3-H1 D3 Sub 2
H1H1-Detail 3-H1 D3 Sub 1
H1H1-Detail 3-H1 D3 Sub 2
H1H1-Detail 3-H1 D3 Sub 1
H1H1-Detail 3-H1 D3 Sub 2
H2-Header 2
H2H2-Detail 1
H2H2-Detail 1-H2 D1 Sub 1
H2H2-Detail 1-H2 D1 Sub 2
H2H2-Detail 2
H2H2-Detail 2-H2 D2 Sub 1
H2H2-Detail 2-H2 D2 Sub 2
H2H2-Detail 3
H2H2-Detail 3-H2 D3 Sub 1
H2H2-Detail 3-H2 D3 Sub 2
H2H2-Detail 3-H2 D3 Sub 1
H2H2-Detail 3-H2 D3 Sub 2
H2H2-Detail 3-H2 D3 Sub 1
H2H2-Detail 3-H2 D3 Sub 2
H2H2-Detail 3-H2 D3 Sub 1
H2H2-Detail 3-H2 D3 Sub 2
H3-Header 3
H3H3-Detail 1
H3H3-Detail 1-H3 D1 Sub 1
H3H3-Detail 1-H3 D1 Sub 2
H3H3-Detail 2
H3H3-Detail 2-H3 D2 Sub 1
H3H3-Detail 2-H3 D2 Sub 2
H3H3-Detail 3
H3H3-Detail 3-H3 D3 Sub 1
H3H3-Detail 3-H3 D3 Sub 2
*/
 
On Mon, Mar 23, 2026 at 7:17 AM 'Nenad Batoćanin' via Harbour Users <
Atul <atul...@gmail.com>: Mar 23 04:52AM -0700

Thank you, Francesco Perillo.
 
You're right about *member access being slower*.
 
I tried another approach as shown below:
 
FOR EACH oHdr IN aHeaders
? "Header : " + oHdr:cHeaderKey + " Customer: " + oHdr:cCustName
FOR EACH oDtl IN oHdr:aDetails
? " Detail : " + oDtl:cDetailKey + " Amt: " + hb_ntos( oDtl:nAmount
)
FOR EACH oSub IN oDtl:aSubs
? " Sub : " + oSub:cSubKey + " Sub amount: " + hb_ntos(
oSub:nSubAmt )
nGrandTotal += oSub:nSubAmt
NEXT
NEXT
NEXT
 
This approach is faster than the previous one — it now takes around *3–4
minutes* to process the same data. However, I would like to optimize it
further if possible.
 
This could be an alternative to the *code + key* approach.
 
The relationship between Header, Detail, and Sub is *one-to-many*, so I
have to loop through all records to calculate the grand total amount.
 
I also tried using a *hash*, but it turned out to be slower than the
class-based approach.
 
Regards, Atul
On Saturday, March 21, 2026 at 5:03:12 PM UTC+5:30 Francesco Perillo wrote:
 
Francesco Perillo <fper...@gmail.com>: Mar 23 12:54PM +0100

But you are not doing any filtering in this version of the code !!!
 
Atul <atul...@gmail.com>: Mar 23 04:58AM -0700

In *Phase 1* of data collection, I have already taken care of adding
aDetails to aHeader and aSubs to aDetail, so there is no need to filter or
scan separately.
 
On Monday, March 23, 2026 at 5:25:11 PM UTC+5:30 Francesco Perillo wrote:
 
Francesco Perillo <fper...@gmail.com>: Mar 23 01:18PM +0100

And since you are filtering in phase1 why don't you do all the math in that
phase ?
 
Sorry, as I said there are several missing informations that you have and
know better why you did some choices.
 
Francesco
 
Atul <atul...@gmail.com>: Mar 23 05:46AM -0700

That's a great point, Francesco.
 
The reason is that I am refactoring my code following *Hexagonal
Architecture*, where I want to clearly separate the *Model*, *UI*, *Core*,
and *Adapter* layers.
 
- *Phase 1* is the *Adapter* layer — responsible for data collection and
preparation.
- *Phase 2* is the *Core / Service* layer — responsible for business
logic, including all the math and calculations.
- *Phase 3* is the *UI* layer — responsible for displaying the report.
 
By keeping these layers separate, I can easily replace the Adapter in the
future with any other data source or technology, such as *SQL*, without
touching the business logic or the presentation layer.
 
Thanks, Atul
 
On Monday, March 23, 2026 at 5:49:12 PM UTC+5:30 Francesco Perillo wrote:
 
Alex Strickland <ss...@mweb.co.za>: Mar 23 09:16AM +0200

Hi
 
I don't know about psychosis, but the results from my limited experience
with Opus 4.6 are astounding.
 
You can't turn back the clock but I kind of wish I could.
 
--
 
Regards
 
Alex
 
 
 
antonio....@gmail.com <antonio....@gmail.com>: Mar 22 03:20PM -0700

[image: transformer1.jpg]
[image: transformer2.jpg]
antonio....@gmail.com <antonio....@gmail.com>: Mar 22 03:27PM -0700

[image: repo.jpg]
 
El domingo, 22 de marzo de 2026 a las 23:20:16 UTC+1, antonio....@gmail.com
escribió:
 
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to harbour-user...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages