Muchas gracias Osvaldo por participar :D
Sevilla - AndalucĂa
Muchas gracias Osvaldo por participar :D
The classical ones
DBF SQLite SQL
=====>
Bayron Landaverry
xBasePHP.com
(215)2226600 Philadelphia,PA, USA
MayaBuilders@gMail.com
Guatemala
FWH25.06--Harbour 3.0.0--BCC7.7--UEstudio 10.10
Windows 10
FiveWin, One line of code and it's done...
============================================================
DATABASE SURVEY — FiveWin/Harbour Community
TABLE 1 — What databases do you currently use?
(multiple answers allowed, 21 participants)
| Database / Engine | Users | % of Respondents |
|---|---|---|
| MySQL / MariaDB | 15 | 71.4 % |
| DBF / Clipper / xBase | 13 | 61.9 % |
| SQL Server | 4 | 19.0 % |
| PostgreSQL | 4 | 19.0 % |
| MS Access | 3 | 14.3 % |
| SQLite | 3 | 14.3 % |
| Oracle | 2 | 9.5 % |
| ADS (Advantage DB Server) | 2 | 9.5 % |
| Other (ArangoDB, etc.) | 1 | 4.8 % |
| MongoDB | 0 | 0.0 % |
| Firebird | 0 | 0.0 % |
Calculation base: 21 unique participants
TABLE 2 — What database would you consider for your
next project or migration? (max. 2 options)
| Database / Engine | Mentions |
|---|---|
| MySQL / MariaDB | 9 |
| PostgreSQL | 5 |
| None / Staying with what I have | 4 |
| DBF / xBase / ADS | 3 |
| SQLite | 2 |
| SQL Server | 1 |
TABLE 3 — MOST IMPORTANT features in a database
access library (max. 3 options)
| Feature | Mentions |
|---|---|
| Access speed and performance | 9 |
| Simple and clear syntax | 6 |
| Complete and updated documentation | 4 |
| Clear and detailed error handling | 3 |
| Practical examples and use cases | 3 |
| Robust transaction support | 2 |
| Automatic connection/pool management | 2 |
| Multi-engine SQL compatibility | 1 |
| ORM support | 1 |
| Active technical support | 1 |
| Integrated debugging tools | 1 |
TABLE 4 — What holds you back from migrating?
(optional, qualitative)
| Reason | Mentions |
|---|---|
| No migration planned | 4 |
| Very large existing codebase | 3 |
| Clients satisfied / no demand | 2 |
| Time needed to learn something new | 2 |
| Complexity of gradual migration | 1 |
Let's be honest: one of the weakest points holding back Harbour's growth is the lack of a modern, unified and native solution for database access. We rely on partial, outdated or third-party solutions that are not always kept up to date. That has to change.
The idea is clear and ambitious: one single library, one single API, one single way of working, regardless of the database engine underneath. No need to relearn anything when switching engines. No engine-specific code. No surprises. Your application talks to the library, and the library talks to the database. Simple as that.
Need to migrate from SQLite to PostgreSQL? Change one line of configuration. Your client runs SQL Server but you develop with MariaDB? Doesn't matter. The code is the same. Always.
These would be the supported engines:
MySQL / MariaDB — The most popular duo in the open source world
PostgreSQL — Enterprise-grade power and reliability
SQL Server — Essential in corporate environments
Oracle — The giant of enterprise databases
SQLite / SQLCipher / SQLiteMC — Lightweight, embedded and with encryption
Firebird / InterBase — A classic beloved by our community
ODBC — The open door to any other engine
A library like this would not only make every Harbour developer's daily work easier, but would open the door to more ambitious projects, attract new developers to the community and prove that Harbour is still a relevant and competitive platform.
I am ready to develop this library, but I need your financial support to make it happen.
If you use Harbour professionally, you know exactly how much value something like this would bring to your daily work and to your clients. A small contribution from each of us can become a tool that benefits us all.
Are you willing to financially support this project? Reply in this thread or contact me privately and we will figure out how to make it work. Together we can make it happen.
xmanuel wrote:
🚀 Isn't it time Harbour had a database library worthy of its community?Let's be honest: one of the weakest points holding back Harbour's growth is the lack of a modern, unified and native solution for database access. We rely on partial, outdated or third-party solutions that are not always kept up to date. That has to change.
The idea is clear and ambitious: one single library, one single API, one single way of working, regardless of the database engine underneath. No need to relearn anything when switching engines. No engine-specific code. No surprises. Your application talks to the library, and the library talks to the database. Simple as that.
Need to migrate from SQLite to PostgreSQL? Change one line of configuration. Your client runs SQL Server but you develop with MariaDB? Doesn't matter. The code is the same. Always.
These would be the supported engines:
MySQL / MariaDB — The most popular duo in the open source world
PostgreSQL — Enterprise-grade power and reliability
SQL Server — Essential in corporate environments
Oracle — The giant of enterprise databases
SQLite / SQLCipher / SQLiteMC — Lightweight, embedded and with encryption
Firebird / InterBase — A classic beloved by our community
ODBC — The open door to any other engine
A library like this would not only make every Harbour developer's daily work easier, but would open the door to more ambitious projects, attract new developers to the community and prove that Harbour is still a relevant and competitive platform.
I am ready to develop this library, but I need your financial support to make it happen.
If you use Harbour professionally, you know exactly how much value something like this would bring to your daily work and to your clients. A small contribution from each of us can become a tool that benefits us all.
Are you willing to financially support this project? Reply in this thread or contact me privately and we will figure out how to make it work. Together we can make it happen.
💬
It would be excellent to have a library with these features, one that would allow for the very simple migration of an application from one database to another.
From my small country and with my limited resources, I would be willing to collaborate on its development.
Now I have applicacionts that works with MariaDb y SqlServer both together and I have to use por it diferent sintaxis and methods.
xmanuel wrote:
🚀 Isn't it time Harbour had a database library worthy of its community?Let's be honest: one of the weakest points holding back Harbour's growth is the lack of a modern, unified and native solution for database access. We rely on partial, outdated or third-party solutions that are not always kept up to date. That has to change.
The idea is clear and ambitious: one single library, one single API, one single way of working, regardless of the database engine underneath. No need to relearn anything when switching engines. No engine-specific code. No surprises. Your application talks to the library, and the library talks to the database. Simple as that.
Need to migrate from SQLite to PostgreSQL? Change one line of configuration. Your client runs SQL Server but you develop with MariaDB? Doesn't matter. The code is the same. Always.
These would be the supported engines:
MySQL / MariaDB — The most popular duo in the open source world
PostgreSQL — Enterprise-grade power and reliability
SQL Server — Essential in corporate environments
Oracle — The giant of enterprise databases
SQLite / SQLCipher / SQLiteMC — Lightweight, embedded and with encryption
Firebird / InterBase — A classic beloved by our community
ODBC — The open door to any other engine
A library like this would not only make every Harbour developer's daily work easier, but would open the door to more ambitious projects, attract new developers to the community and prove that Harbour is still a relevant and competitive platform.
I am ready to develop this library, but I need your financial support to make it happen.
If you use Harbour professionally, you know exactly how much value something like this would bring to your daily work and to your clients. A small contribution from each of us can become a tool that benefits us all.
Are you willing to financially support this project? Reply in this thread or contact me privately and we will figure out how to make it work. Together we can make it happen.
💬
The Harbour project supports ORM (Object-Relational Mapping) functionality through a specialized project called Harbour_ORM.
FiveWin has its own layer of ORM.
=====>
Bayron Landaverry
xBasePHP.com
(215)2226600 Philadelphia,PA, USA
MayaBuilders@gMail.com
Guatemala
FWH25.06--Harbour 3.0.0--BCC7.7--UEstudio 10.10
Windows 10
FiveWin, One line of code and it's done...
Here you go:
That is correct, and it is worth noting that HDBC (Harbour Database Connections) takes things a step further by offering three different levels of data access within a single framework, giving the developer the freedom to choose the approach that best fits each situation:
1. Direct Access (API Level)
Uses classes as wrappers for the native C APIs of each engine (MySQL, PostgreSQL, SQLite, Oracle, etc.). Maximum speed and control, but tied to a specific database engine.
2. ORM (Object-Relational Mapping)
Similar to what Harbour_ORM and FiveWin offer, tables are treated as objects and rows as class instances. Clean, readable code without writing SQL directly.
3. RDD-Style Access
This is where HDBC really stands out. It allows you to use the traditional Clipper/Harbour RDD commands and functions directly against modern SQL databases, with no explicit SQL required. Any developer familiar with Clipper will feel right at home:
[]Navigation:
DbGoTop(), DbGoBottom(), DbSkip(), GO TOP, SKIP +1[]Area control:
DbSelectArea(), DbCloseArea(), SELECT 0, USE ... SHARED[]Data manipulation:
DbAppend(), DbDelete(), DbRecall(), APPEND BLANK, DELETE, REPLACE field WITH value[]Searches and indexes:
DbSeek(), DbSetIndex(), OrdSetFocus(), SEEK, SET ORDER TOField access:
FieldGet(n), FieldPut(n, value), ALIAS->FieldThe three approaches are not mutually exclusive and can be combined within the same project. Whether you need raw performance, clean object-oriented code, or the familiarity of classic Clipper syntax against a modern SQL backend, HDBC has you covered.
To illustrate the three approaches, here is a practical example of how to create a table using each one:
1. Direct Access (API Level) — SQL specific to the engine
Full control, but you must write SQL adapted to each database engine (in this case, Oracle):
LOCAL cCreateTable
TEXT INTO cCreateTable
CREATE TABLE test
(
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
first VARCHAR2( 20 ),
last VARCHAR2( 20 ),
street VARCHAR2( 30 ),
city VARCHAR2( 30 ),
state VARCHAR2( 2 ),
zip VARCHAR2( 10 ),
hiredate DATE,
married NUMBER(1),
age NUMBER(3),
salary NUMBER( 9, 2 ),
notes VARCHAR2( 70 )
)
ENDTEXT
IF oDb:exec( cCreateTable ) == -1
? "Error creating table:", oDb:lastError()
BREAK
ENDIF
oDb:commit()2. ORM — Database independent
No SQL needed. The same code works regardless of the database engine running behind the scenes:
THSchema():new( "test_products" ):dropIfExists()
oSchema := THSchema():new( "test_products" )
oSchema:add( THField():id() )
oSchema:add( THField():string( "name" ) )
oSchema:add( THField():float( "price" ) )
oSchema:add( THField():integer( "stock" ) )
oSchema:add( THField():string( "category" ) )
oSchema:create()3. RDD Style — Classic Clipper/Harbour syntax
Familiar to any Clipper developer. Define the structure as an array and let HDBC handle the rest:
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 )As you can see, all three approaches achieve the same result. The choice depends on how much control you need and how familiar you are with each style.
HDBC RDD - Example 01: Basic Operations
Imagine this code working against Oracle, Postgres, MySQL and more — without changing a single comma.
//-----------------------------------------------------------------------------
// Project: Harbour Data Base Connection (HDBC)
// File: rdd_ex01.prg
// Author: Manu Exposito (2026)
// Notes: Example 01: Basic Operations (Connection, dbCreate, CRUD)
// This example shows how to get started with the HDBC RDD.
//-----------------------------------------------------------------------------
#include "hdbc.ch"
#include "rddsys.ch"
// --- CENTRALIZED CONFIGURATION ---
#include "../otros/hdbc_config.ch"
PROCEDURE Main()
local oDbc, nTotal, oErr
local aStruct := { ;
{ "ID", "N", 10, 0 }, ;
{ "NOMBRE", "C", 50, 0 }, ;
{ "SALARIO", "N", 12, 2 }, ;
{ "FECHA", "D", 8, 0 }, ;
{ "ACTIVO", "L", 1, 0 } ;
}
try
// 1. CONNECTION SETUP
// --------------------------------------------------------------------------
oDbc := THDbc():new( _DRIVER_ )
hb_cdpSelect( "UTF8" )
CLS
? "HDBC RDD - EXAMPLE 01: BASIC OPERATIONS (" + Upper( oDbc:driverName() ) + ")"
? Replicate( "-", 60 )
?
oDbc:setAttribute( HDBC_ATTR_CONNECTION_STRING, _CONN_STRING_ )
if ! oDbc:connect()
? "Error connecting to database:", oDbc:lastError()
else
? "Connected to:", _CONN_STRING_
// 2. RDD REGISTRATION AND INITIALIZATION
// --------------------------------------------------------------------------
rddRegister( "RDDHDBC", RDT_FULL )
HDbcRdd_Init( oDbc )
RddSetDefault( "RDDHDBC" )
// 3. TABLE CREATION (dbCreate)
// --------------------------------------------------------------------------
? "Creating table 'empleados'..."
dbCreate( "empleados", aStruct )
// 4. OPENING THE TABLE (dbUseArea / USE)
// --------------------------------------------------------------------------
USE empleados ALIAS EMP VIA "RDDHDBC" NEW
if NetErr()
? "Error opening table 'empleados'"
else
// 5. CRUD OPERATIONS (Create, Read, Update, Delete)
// --------------------------------------------------------------------------
? "Inserting 5 records (CREATE)..."
SELECT EMP
APPEND BLANK
REPLACE FIELD->ID WITH 1, ;
FIELD->NOMBRE WITH "Juan Pérez", ;
FIELD->SALARIO WITH 2500.50, ;
FIELD->FECHA WITH Date(), ;
FIELD->ACTIVO WITH .T.
APPEND BLANK
REPLACE FIELD->ID WITH 2, ;
FIELD->NOMBRE WITH "Maria GarcĂa", ;
FIELD->SALARIO WITH 3200.75, ;
FIELD->FECHA WITH Date() - 30, ;
FIELD->ACTIVO WITH .T.
APPEND BLANK
REPLACE FIELD->ID WITH 3, ;
FIELD->NOMBRE WITH "Carlos RodrĂguez", ;
FIELD->SALARIO WITH 2800.00, ;
FIELD->FECHA WITH Date() - 15, ;
FIELD->ACTIVO WITH .T.
APPEND BLANK
REPLACE FIELD->ID WITH 4, ;
FIELD->NOMBRE WITH "Ana MartĂnez", ;
FIELD->SALARIO WITH 3500.00, ;
FIELD->FECHA WITH Date() + 1, ;
FIELD->ACTIVO WITH .T.
APPEND BLANK
REPLACE FIELD->ID WITH 5, ;
FIELD->NOMBRE WITH "Pedro LĂłpez", ;
FIELD->SALARIO WITH 2100.25, ;
FIELD->FECHA WITH Date() - 10, ;
FIELD->ACTIVO WITH .T.
? "Current listing:"
COUNT TO nTotal
? "Total records:", nTotal
EMP->( dbGoTop() )
DO WHILE ! EMP->( Eof() )
? " ID:", EMP->ID, "Name:", PadR( EMP->NOMBRE, 16 ), "Salary:", EMP->SALARIO
EMP->( dbSkip() )
ENDDO
?
? "Updating salary for ID 1..."
GOTO 1
IF EMP->ID == 1
REPLACE EMP->SALARIO WITH EMP->SALARIO + 500
? "Juan's new salary:", EMP->SALARIO
ENDIF
? "Deleting record 2..."
GOTO 2
DELETE
? "Record 2 marked as deleted. Deleted():", Deleted()
endif
endif
catch oErr
? "AN ERROR HAS OCCURRED:"
? " GenCode: ", oErr:genCode
? " SubCode: ", oErr:subCode
? " Desc: ", oErr:description
? " Operation:", oErr:operation
end
// 6. CLEANUP AND CLOSE
// --------------------------------------------------------------------------
?
? "Closing everything..."
CLOSE ALL
IF oDbc != NIL
oDbc:disconnect()
ENDIF
HDbcRdd_End()
? "Example finished."
espera()
returnWhat does this example do?
All the magic is concentrated in just three key lines:
oDbc := THDbc():new( _DRIVER_ )
oDbc:setAttribute( HDBC_ATTR_CONNECTION_STRING, _CONN_STRING_ )
oDbc:connect()By only changing DRIVER and CONN_STRING in the configuration file hdbc_config.ch, the exact same code runs against Oracle, PostgreSQL, MySQL, MariaDB, SQLite... whatever you need. The rest of the program stays untouched.
From there, everything is plain classic Harbour:
dbCreate() creates the table on the target engine
USE ... VIA "RDDHDBC" opens it just like a DBF
APPEND BLANK / REPLACE insert records (INSERT)
DO WHILE / dbSkip() iterate through the cursor (SELECT)
REPLACE on a positioned record updates it (UPDATE)
DELETE marks the record as deleted, xBase style (DELETE)
The RDD takes care of translating all of that into SQL at runtime. From the developer's perspective, it feels exactly like working with good old DBFs. On the database side, correct native SQL statements arrive. Best of both worlds.
ORM
//-----------------------------------------------------------------------------
// Proyecto: Harbour Data Base Connection (HDBC)
// Archivo: orm_test03.prg
// Autor: Manu Exposito (2026)
// Notas: TEST MAESTRO 03 - Persistencia & Transacciones
//-----------------------------------------------------------------------------
#include "hbclass.ch"
#include "hdbc.ch"
#include "../otros/hdbc_config.ch"
//-----------------------------------------------------------------------------
// MODELO SIMPLE
//-----------------------------------------------------------------------------
CLASS FinalModel FROM THModel
DATA table_name INIT "test_crud"
DATA id, name
ENDCLASS
procedure main()
local oDb, oUser, e, lOk, oTmp1, oTmp2
try
oDb := THDbc():new( _DRIVER_ )
if oDb:driverName() == "HDBCFIREBIRD"
oDb:setAttribute( HDBC_ATTR_FB_DIALECT, 3 )
endif
oDb:connect( _CONN_STRING_ )
THModel():setConnection( oDb )
cls
? "=========================================================="
? "TEST MAESTRO 03: PERSISTENCIA & TRANSACCIONES"
? "DRIVER: (" + Upper( oDb:driverName() ) + ")"
? "=========================================================="
?
// Preparar Tabla
THSchema():new( "test_crud" ):dropIfExists()
THSchema():new( "test_crud" ):add( THField():id() ):add( THField():string( "name" ) ):create()
// ====================================================================
// PARTE 1: CICLO CRUD COMPLETO
// ====================================================================
? "PARTE 1: Ciclo CRUD Completo"
? "----------------------------"
// C - CREATE
oUser := FinalModel():create({ "name" => "ORIGINAL" })
? " - [C] Creado ID:", oUser:id
// R - READ
oUser := FinalModel():find( oUser:id )
? " - [R] Leido nombre:", oUser:name
// U - UPDATE
oUser:name := "MODIFICADO"
oUser:save()
? " - [U] Nombre actualizado a:", FinalModel():find( oUser:id ):name
// D - DELETE
oUser:delete()
? " - [D] Borrado. Quedan:", FinalModel():count()
// ====================================================================
// PARTE 2: MOTOR DE TRANSACCIONES
// ====================================================================
?
? "PARTE 2: Motor de Transacciones"
? "--------------------------------"
// A) TransacciĂłn Exitosa (Commit)
? " A) Transaccion Exitosa (Commit):"
lOk := FinalModel():transaction({|| ;
( QOut( " - Dentro de transaccion... creando 2 registros." ), ;
oTmp1 := FinalModel():create({ "name" => "Trans 1" }), ;
oTmp2 := FinalModel():create({ "name" => "Trans 2" }), ;
.T. ) ;
})
? " - Resultado:", lOk, "| Registros en BD:", FinalModel():count()
// B) TransacciĂłn Fallida (Rollback)
?
? " B) Transaccion Fallida (Rollback):"
lOk := FinalModel():transaction({|| ;
( QOut( " - Dentro de transaccion... intentando crear y fallar." ), ;
oTmp1 := FinalModel():create({ "name" => "No debe existir" }), ;
QOut( " - Forzando ROLLBACK retornando .F." ), ;
.F. ) ;
})
? " - Resultado:", lOk, "| Registros en BD:", FinalModel():count()
// ====================================================================
// PARTE 3: MODERNIZACIÓN Y ROBUSTEZ
// ====================================================================
?
? "PARTE 3: Modernizacion y Robustez (UPSERT & Mutable)"
? "----------------------------------------------------"
// 1. UPSERT (Update or Insert)
? " A) Sincronizacion de datos (upsert):"
FinalModel():new():upsert({ "name" => "SYNC_USER" }, { "id" => 999 })
? " - Registro creado mediante UPSERT. ID:", FinalModel():where("name","=","SYNC_USER"):first():id
FinalModel():new():upsert({ "name" => "SYNC_USER" }, { "name" => "SYNC_UPDATED" })
? " - Registro actualizado mediante UPSERT. Nuevo nombre:", FinalModel():find(999):name
// 2. Modo Mutable (Rendimiento)
?
? " B) Optimizacion (Modo Mutable):"
oUser := FinalModel():new()
oUser:mutable(.T.)
oUser:where("id", ">", 0):order("name ASC")
? " - Query Builder configurado en modo mutable."
? " - Resultados encontrados:", oUser:count()
?
? "=========================================================="
? "TEST 03 COMPLETADO EXITOSAMENTE"
? "=========================================================="
?
? "SUITE DE TESTS COMPLETADA CON EXITO!"
catch e
? "ERROR:", e:description
finally
oDb:disconnect()
THModel():end()
espera()
end
returnGentleman .. Lets not forget the operating system we are running our database applications on .. everything I see posted on this thread has to run on a Windows ( primarily desktop ) operation system .. what about Mac, what about Linux ?
Unfortunately there is no one database development platform that will be a single panacea that will create an app that will run on ALL computer systems .. hence you will still see multiple programming development platforms ..
So generally speaking we develop applications that run on our Customer's computer systems .. and I do not see ( in the future ) that one shoe ( development platform ) that will fit all ...
Rick Lipkin
Dear Rick,
Just a reminder that we have FiveLinux and FiveMac and that they work great :idea:
If you use DBFs and/or SQL then you can easily have your Harbour app running on any operating system :wink:
Antonio
Thank you for the update .. I am a Windows person and usually do not look for other solutions .. I appreciate your answer and perhaps other users may need to know You have all the bases covered ..
Thanks again Rick Lipkin
Hey guys,
I just want to share my experience with Manu's solution. It is an amazing tool! I have been using it for years (since HDO), and now with HDBC. I already have it running on Windows, Linux, macOS, iOS, Android, and Raspberry Pi.
It is very easy to use and fast!
I highly recommend you try it. It is affordable and can improve the quality of your project.
Dear Rick,
If you're a Harbour developer, you already know the pain of dealing with database connectivity that feels bolted on as an afterthought. HDBC changes that.
Built entirely in standard C++, HDBC runs natively wherever Harbour runs — Windows, Linux, and macOS, in both 32-bit and 64-bit environments. No compromises, no platform headaches. Just write your code once and deploy it anywhere your users need it.
Whether you're maintaining a legacy xBase system or building something new on Harbour's solid foundation, HDBC gives you a clean, consistent database layer that feels like it was always meant to be there — because it was.
Give it a try. Your database code will thank you.
Versión en español
Estimado Rick,
Si desarrollas con Harbour, sabes bien lo frustrante que puede llegar a ser la conectividad con bases de datos. HDBC está aquà para cambiar eso.
Construido Ăntegramente en C++ estándar, HDBC funciona de forma nativa en cualquier plataforma donde corra Harbour — Windows, Linux y macOS, tanto en 32 como en 64 bits. Sin concesiones, sin dolores de cabeza por compatibilidad. Escribe tu cĂłdigo una vez y despliĂ©galo donde tus usuarios lo necesiten.
Tanto si mantienes un sistema heredado en xBase como si estás construyendo algo nuevo sobre la sĂłlida base de Harbour, HDBC te ofrece una capa de acceso a datos limpia y consistente que parece haber estado siempre ahà — porque es exactamente donde deberĂa estar.
Pruébalo. Tu código de base de datos te lo agradecerá.
:D