cookbook(orm): fast-queries DBF example (index-ordered nav + AOF) + vendored ORM refresh#95
Conversation
…efresh vendored navexec/hbo_ace New DBF example demonstrating the ORM's navigational fast paths: index-ordered navigation (ORDER BY an indexed column walks in index order, LIMIT stops early, ranges become AdsSetScope index bounds) and the Advantage Optimized Filter (WHERE pushed to the engine). It proves the optimized path fired via the ORM instrumentation counters. Refreshes the vendored examples/orm/src/navexec.prg and hbo_ace.prg from the companion ORM so the example builds with the AOF/OrdScope code. Builds and runs green against the engine.
There was a problem hiding this comment.
Code Review
This pull request introduces navigational fast paths (OrdScope and Advantage Optimized Filters) for the Harbour ORM over OpenADS, including a cookbook example, new ACE API wrappers in C, and query optimization logic in navexec.prg. The review feedback highlights critical safety issues in the newly added C functions (HBO_DDGETFIELDPROP, HBO_DDCREATE, HBO_DDADDTABLE, and HBO_DDSETFIELDPROP) where string parameters retrieved via hb_parc are not checked for NULL before being passed to the underlying ACE APIs, which could result in segmentation faults if parameters are omitted or passed as NIL.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if( AdsDDGetFieldProperty( ( ADSHANDLE ) hb_parnint( 1 ), | ||
| ( UNSIGNED8 * ) hb_parc( 2 ), ( UNSIGNED8 * ) hb_parc( 3 ), | ||
| ( UNSIGNED16 ) hb_parni( 4 ), szBuf, &usLen ) == 0 ) |
There was a problem hiding this comment.
The parameters cTable (parameter 2) and cField (parameter 3) retrieved via hb_parc can be NULL if they are omitted or passed as NIL. Passing NULL directly to AdsDDGetFieldProperty will cause a segmentation fault / crash. We should check both pointers for NULL before calling the API.
const char * szTable = hb_parc( 2 );
const char * szField = hb_parc( 3 );
if( szTable && szField && AdsDDGetFieldProperty( ( ADSHANDLE ) hb_parnint( 1 ),
( UNSIGNED8 * ) szTable, ( UNSIGNED8 * ) szField,
( UNSIGNED16 ) hb_parni( 4 ), szBuf, &usLen ) == 0 )
| ADSHANDLE hConn = 0; | ||
| UNSIGNED32 ulRc = AdsDDCreate( ( UNSIGNED8 * ) hb_parc( 1 ), 0, NULL, &hConn ); | ||
| hb_retnint( ulRc == 0 ? ( HB_MAXINT ) hConn : 0 ); |
There was a problem hiding this comment.
The parameter cDictPath (parameter 1) retrieved via hb_parc can be NULL if omitted or passed as NIL. Passing NULL directly to AdsDDCreate will cause a segmentation fault / crash. We should check the pointer for NULL before calling the API.
const char * szPath = hb_parc( 1 );
ADSHANDLE hConn = 0;
UNSIGNED32 ulRc = 1;
if( szPath )
ulRc = AdsDDCreate( ( UNSIGNED8 * ) szPath, 0, NULL, &hConn );
hb_retnint( ulRc == 0 ? ( HB_MAXINT ) hConn : 0 );
| hb_retl( AdsDDAddTable( ( ADSHANDLE ) hb_parnint( 1 ), | ||
| ( UNSIGNED8 * ) hb_parc( 2 ), ( UNSIGNED8 * ) hb_parc( 3 ), | ||
| 0, 0, NULL, NULL ) == 0 ); |
There was a problem hiding this comment.
The parameters cAlias (parameter 2) and cTablePath (parameter 3) retrieved via hb_parc can be NULL if omitted or passed as NIL. Passing NULL directly to AdsDDAddTable will cause a segmentation fault / crash. We should check both pointers for NULL before calling the API.
const char * szAlias = hb_parc( 2 );
const char * szPath = hb_parc( 3 );
hb_retl( szAlias && szPath && AdsDDAddTable( ( ADSHANDLE ) hb_parnint( 1 ),
( UNSIGNED8 * ) szAlias, ( UNSIGNED8 * ) szPath,
0, 0, NULL, NULL ) == 0 );
| hb_retl( AdsDDSetFieldProperty( ( ADSHANDLE ) hb_parnint( 1 ), | ||
| ( UNSIGNED8 * ) hb_parc( 2 ), ( UNSIGNED8 * ) hb_parc( 3 ), | ||
| ( UNSIGNED16 ) hb_parni( 4 ), | ||
| ( void * ) hb_parc( 5 ), ( UNSIGNED16 ) hb_parclen( 5 ) ) == 0 ); |
There was a problem hiding this comment.
The parameters cTable (parameter 2), cField (parameter 3), and cValor (parameter 5) retrieved via hb_parc can be NULL if omitted or passed as NIL. Passing NULL directly to AdsDDSetFieldProperty will cause a segmentation fault / crash. We should check all three pointers for NULL before calling the API.
const char * szTable = hb_parc( 2 );
const char * szField = hb_parc( 3 );
const char * szVal = hb_parc( 5 );
hb_retl( szTable && szField && szVal && AdsDDSetFieldProperty( ( ADSHANDLE ) hb_parnint( 1 ),
( UNSIGNED8 * ) szTable, ( UNSIGNED8 * ) szField,
( UNSIGNED16 ) hb_parni( 4 ),
( void * ) szVal, ( UNSIGNED16 ) hb_parclen( 5 ) ) == 0 );
Adds a new cookbook example
cookbook/orm/dbf/fast_queries_dbf.prgshowing the companion ORM's two navigational fast paths on a DBF back-end, and refreshes the vendored ORM sources it needs.What it demonstrates (all automatic — same query builder, no new API)
ORDER BYan indexed column walks the table in index order instead of reading every row and sorting in memory, soORDER BYis free andLIMITstops early. A range on the ordered column is pushed to the engine as an index scope (AdsSetScope).WHEREin the optimizable subset (= != < <= > >=,IN,AND/ORof those) is pushed to the engine's AOF; in client/server mode only matching rows travel the wire.The example reads the ORM's instrumentation counters to prove the optimized path actually fired (e.g. "top 5 by balance ... records walked: 5 of 12 (stopped early)").
Files
cookbook/orm/dbf/fast_queries_dbf.prg— new example (English, same style ascrud_dbf.prg).examples/orm/src/navexec.prg,examples/orm/src/hbo_ace.prg— refreshed from the companion ORM (brings the AOF + OrdScope code).Verification
Builds and runs green against the engine (DBF back-end), exit 0; all sections produce correct, ordered results and the counters confirm early-stop and server-side filtering.