The HDBC RDD (RDDHDBC) is a powerful engine allowing Harbour developers to interact with any HDBC-connected SQL database uniformly mapping classic xBase commands (USE, APPEND BLANK, REPLACE, SKIP, SEEK, SET FILTER, etc.).
This bridging layer translates your procedural legacy operations dynamically down into native dialects fitting your configured backing engine (SQLite, MySQL, PostgreSQL, etc.). It acts as a perfect gateway for porting existing applications or satisfying developers refusing direct object-oriented manual SQL interactions.
--- 1. Initial Setup and Driver InjectionTo begin leveraging WorkAreas, bind your globally instantiated THDbc connection underlying the Harbour core RDD subsystem.
Code: Select all | Expand
#include "hdbc_conn.ch"
#include "hdbc.ch"
#include "rddsys.ch"
PROCEDURE Main()
LOCAL oDbc := THDbc():new( HDBC_DRIVER_SQLITE )
oDbc:connect( "database=test_rdd.db" )
// 1. Register the core architecture internally
rddRegister( "RDDHDBC", RDT_FULL )
// 2. Cascade your active connection stream down to the RDD scope
HDbcRdd_Init( oDbc )
// 3. (Optional) Force all standard commands to ride this driver
RddSetDefault( "RDDHDBC" )--- 2. Basic xBase Operations (CRUD) 2.1 Table Generation (dbCreate)[!TIP]
Before terminating the system scope gracefully, wipe unreleased states utilizing HDbcRdd_End() before concluding THDbc disconnect logic.
You can architect remote structures directly by feeding a standard structural array blueprint extended with the specialized TIMESTAMP type natively.
Code: Select all | Expand
LOCAL aStruct := { ;
{ "ID", "N", 10, 0 }, ;
{ "NAME", "C", 50, 0 }, ;
{ "SALARY", "N", 12, 2 }, ;
{ "DATE", "D", 8, 0 }, ;
{ "ACTIVE", "L", 1, 0 } ;
}
dbCreate( "employees", aStruct, "RDDHDBC" )Code: Select all | Expand
USE employees ALIAS EMP VIA "RDDHDBC" NEW
IF NetErr()
? "Server failed handling remote table mount"
ENDIFCode: Select all | Expand
SELECT EMP
APPEND BLANK
REPLACE FIELD->ID WITH 1, ;
FIELD->NAME WITH "John Doe", ;
FIELD->SALARY WITH 2500.50, ;
FIELD->ACTIVE WITH .T.Code: Select all | Expand
EMP->( dbGoTop() )
DO WHILE ! EMP->( Eof() )
? "ID:", EMP->ID, "Name:", EMP->NAME
EMP->( dbSkip() )
ENDDOWhenever the inner schema observes standard deletion columns (SoftDeletes flag logic), the underlying DELETE routing overrides to UPDATE. Otherwise conventional physically dropping DELETE FROM execution applies natively preventing disk pollution.
Code: Select all | Expand
GOTO 2
DELETE
? "Target instance stripped. Deleted():", Deleted()Create runtime virtual indexing to hasten binary narrowing avoiding sequentially linear sweeps.
Code: Select all | Expand
USE clients ALIAS CLI NEW VIA "RDDHDBC"
INDEX ON FIELD->name TAG query_name
SEEK "Maria Garcia"
IF Found()
? "MATCHED ALIAS! ID:", CLI->id, "City:", CLI->city
ENDIFWhile SET FILTER inherently navigates evaluating record by record, HDBC naturally honors index SCOPES thresholds. Scoping performs logarithmically faster because it intervenes during the early native pre-generation injecting boundaries straight into the SQL request.
Usage of SET FILTER:
Code: Select all | Expand
SET FILTER TO CLI->city == "London"
GO TOP
DO WHILE ! Eof()
? "Located resident:", CLI->name
SKIP
ENDDO
SET FILTER TO // Purge constraintUsage of SCOPES (Smart Indexing Bounds):
Code: Select all | Expand
// Assuming an 'idx_city' tag is created...
ORDSETFOCUS( "idx_city" )
// Lock bounds for TOP (0) and BOTTOM (1)
ORDSCOPE( 0, "London" )
ORDSCOPE( 1, "London" )
GO TOP
// Loop traverses exclusively limited London bounds at lightning speed
ORDSCOPE( 0, NIL ) // Revert top bound wipe outEnforce runtime cascading pointers syncing chained aliases asynchronously while advancing parent cursors step-by-step parallelizing child targets seamlessly.
Code: Select all | Expand
USE invoices ALIAS INV NEW VIA "RDDHDBC"
SELECT CLI
INDEX ON FIELD->id TAG idx_cli
SELECT INV
SET RELATION TO INV->client_id INTO CLI
GO TOP
DO WHILE ! Eof()
// Background translation fetches matching row
? "Order Number:", INV->id, "-> Pertaining Client:", CLI->name
SKIP
ENDDOProbably representing RDDHDBC heaviest lifting trick allowing you to package highly volatile aggregated queries directly transforming results wrapping around purely readable WorkAreas.
Code: Select all | Expand
USE "SELECT c.name, COALESCE(SUM(i.total), 0) as subtotal FROM clients c LEFT JOIN invoices i ON c.id = i.client_id GROUP BY c.id, c.name" ALIAS REPORT NEW VIA "RDDHDBC"
IF Used()
DO WHILE ! Eof()
? "Ledger stats:", REPORT->name, "Subtotal:", REPORT->subtotal
SKIP
ENDDO
CLOSE REPORT
ENDIFNative RDDHDBC logic heavily relies upon the initialized driver bounds.
Transaction WrappingUtilize master oDbc object hooks enclosing blocks strictly honoring RDMS ACID specifications.
Code: Select all | Expand
oDbc:beginTrans()
REPLACE SEC->balance WITH SEC->balance + 500
IF lSuccess
oDbc:commit()
ELSE
oDbc:rollback()
ENDIFRDDHDBC flawlessly couples Harbour legacy maintenance commands with strict backend architectural standards.
ZAP (Full Truncate)By invoking ZAP, the RDD driver will omit any standard linear DELETE FROM protocol SQL clauses, issuing a definitive native TRUNCATE TABLE command into the targeted engine instead. It resets the database without unnecessarily choking transaction logs (substantially faster).
Code: Select all | Expand
USE audit_trails ALIAS AUD VIA "RDDHDBC" EXCLUSIVE
ZAP
? "Audit table radically truncated back to pristine conditions."In traditional DBFs, PACK compacted empty binary slots sequentially. Within HDBC, if an active session flags "Logical Deletion" features (possessing a compliant trailing deleted_at column), issuing the DELETE command exclusively yields Soft-Deletes modifying the date stamp, leaving real data securely attached remotely.
Enacting the PACK command orchestrates the definitive heavy-duty SQL statement dropping permanently any row previously marked with the logical deletion timeframe, fulfilling purely compliant 1:1 xBase replication workflows.
Code: Select all | Expand
USE clients ALIAS CLI VIA "RDDHDBC" EXCLUSIVE
PACK
? "Database thoroughly sanitized definitively dropping hidden soft-deleted entries."Optionally leverage standard RLock() to tentatively deny writes targeting your mutating tuples if your engine dialect fully orchestrates external transaction locks locking records atomically safely.
Code: Select all | Expand
GO TOP
IF RLock()
REPLACE SEC->balance WITH 2000
UNLOCK
ELSE
? "Overlapping constraint violation. Process stalled remotely."
ENDIFAnd this works with: MySQL, MariaDB, SQLite and clones, Postgres, Oracle, SQLServer, Interbase, Firebird and ODBC. Writing a PRG for any database is now a reality!!!