Page 1 of 1

Presentamos HDBC – La Mejor Conexión a Bases de Datos para Harbour

Posted: Wed Mar 05, 2025 5:18 pm
by Lailton
Hola a todos,

Me complace presentar Harbour Database Connect (HDBC), una nueva y potente librería desarrollada por Manuel Expósito (Manu), un desarrollador altamente experimentado y sofisticado con un profundo conocimiento de Harbour a nivel C.

HDBC es una librería de alto rendimiento escrita en C/C++, diseñada para brindar a los desarrolladores de Harbour máxima velocidad y flexibilidad al conectarse a bases de datos. Con HDBC, puedes acceder fácilmente a PostgreSQL, SQLite y ODBC, y pronto habrá soporte para SQL Server y MySQL/MariaDB—¡con tu apoyo, podemos acelerar su desarrollo!

¿Por qué elegir HDBC?

✅ Núcleo en C/C++ para interacciones con bases de datos de alto rendimiento
✅ Compatible con Harbour puro, FiveWin y modHarbour
✅ Funciona con Harbour 32-bit y 64-bit (BCC/MSVC) – otros compiladores disponibles bajo petición
✅ Soporte para Linux incluido

¡Oferta especial – Promoción por tiempo limitado!

Si compras HDBC este mes, también recibirás HDO a un precio exclusivo. Con HDBC + HDO, tendrás soporte para:
✔ SQLite, SQLCipher, MySQL, MariaDB, PostgreSQL, ODBC y HDORDD

Además, Manuel ofrece 1 año de actualizaciones gratuitas, todo por un precio muy asequible.

📌 Descubre más e inicia hoy mismo: https://harbour.blog/hdbc/

Si tienes alguna pregunta, no dudes en contactarnos.

¡Gracias!

Re: Presentamos HDBC – La Mejor Conexión a Bases de Datos para Harbour

Posted: Wed Mar 05, 2025 6:45 pm
by Carles
Hi,

Felicidades Manu

C.

Re: Presentamos HDBC – La Mejor Conexión a Bases de Datos para Harbour

Posted: Wed Mar 05, 2025 7:00 pm
by sysctrl2
Pinta muy bien,
HDBC LIB, es compatible con xBrowse ? puede mostrar codigo de uso?
gracias.

Re: Presentamos HDBC – La Mejor Conexión a Bases de Datos para Harbour

Posted: Wed Mar 05, 2025 7:18 pm
by Lailton
Hola,

Si, la xBrowse de FiveWin es muy avanzada, y te permite muy facil usar Array para los dados de browse
se verificar los ejemplos en la URL tiene ejemplos de como obter los resultado como array, hash, json etc.

Como siempre la limitacion de harbour es la imaginacion :D

Re: Presentamos HDBC – La Mejor Conexión a Bases de Datos para Harbour

Posted: Wed Mar 05, 2025 8:01 pm
by Marco Augusto
Saludos
puedo usar MYSQL via ADO

Re: Presentamos HDBC – La Mejor Conexión a Bases de Datos para Harbour

Posted: Fri Mar 07, 2025 12:23 am
by xmanuel
De momento solo usa soporte nativo a:
- SQLite y SQLCipher (SQLite cifrado)
- PostgreSQL
- MS SQLServer
- ODBC
En proyecto está:
- MariaDB/MySQL
- Firebird
- Oracle

Todas ellas con accesos nativos, usando el estándar C++20 con los compiladores MSVC 32 y 64, MinGW 32 y 64, CLang 32 y 64 y Bcc 64 (no he probado el de 32 que posiblemente no implemente el C++20)
Para que tengáis una idea estas son las clases virtuales en C++ desde las que derivan las demás especializadas en un base de datos concreta:

Code: Select all | Expand

//-----------------------------------------------------------------------------
// Harbour Data Base Connection (HDBC)
// Archivo: hdbc.hpp
// Clase virtual desde la se derivan todas
// Autor: Manu Exposito (2024)
// Notas:
//-----------------------------------------------------------------------------

#ifndef _HVDBC_HPP
#define _HVDBC_HPP

#pragma once

// De HDbc
#include "hvobject.hpp"
#include "hcompclass.hpp"

// Definicion anticipada de clases
class TVHDbc;
class TVHDbcStmt;

// De C++
#include <string>

//-----------------------------------------------------------------------------
// Clase TVHDbc: Gestion de la conexion y la base de datos

class TVHDbc : public TXVObject
{
	public:
		// Atributos
		HB_UINT ATTR_TIMEOUT = 0; // Tiempo de espera
		HB_UINT ATTR_ERRMODE = 1; // Lanaza exception
		// Metodos
		virtual void init() {}

		virtual bool connect() = 0;
		virtual bool isConnected() const = 0;
		virtual void disconnect() = 0;
		virtual bool reconnect() = 0;
		virtual bool ping();
		virtual TVHDbcStmt *prepare( const char *zSql ) const = 0;
		virtual void query( const char *zSql, PHB_ITEM aColNames ) const;
		virtual void tables() const = 0;
		virtual void scalar( const char *zSql, HB_UINT columnIndex ) const;
		virtual bool setAttribute( HB_UINT uiAttribute, PHB_ITEM xValue );
		virtual PHB_ITEM getAttribute( HB_UINT uiAttribute ) const;
		virtual bool beginTrans() const;
		virtual bool commit() const;
		virtual bool rollback() const;
		virtual HB_INT exec( const char *szStmt ) const = 0;
		virtual HB_INT errorCode() const noexcept = 0;
		virtual const char *lastError() const noexcept = 0;
		virtual HB_SIZE lastInsertId() const;
		virtual std::string escapeStr( const std::string &inputStr ) = 0;
		virtual std::string quote( const std::string &inputStr ) = 0;
		virtual void *gethConn() const = 0;

	protected:
	private:
};

//-----------------------------------------------------------------------------
// Clase TVHDbcStmt: Gestion de sentencias

class TVHDbcStmt : public TXVObject
{
	private:
		HB_UINT uiColumnCount = 0;
		HB_UINT uiParamCount = 0;

	protected:
		TBindList *listParam = nullptr;
		TBindList *listColumn = nullptr;
		int iRowCount = 0;
		int iCurrentRow = -1;

	public:
		// Atributos
		// Los ATTR_ poner en una estructura o en una enumeracion
		HB_UINT ATTR_ERRMODE = 1; // Lanaza exception
		// Metodos
		virtual void close() = 0;
		virtual bool closeCursor() = 0;
		virtual void bindParam( HB_UINT index, PHB_ITEM xParam );
		virtual void bindValue( HB_UINT index, PHB_ITEM xValue );
		virtual void bindColumn( HB_UINT index, PHB_ITEM xColumn );
		virtual bool bindParamC( const char *szIndex, PHB_ITEM xParam );
		virtual bool bindValueC( const char *szIndex, PHB_ITEM xValue );
		virtual HB_INT errorCode() const noexcept = 0;
		virtual const char *lastError() const noexcept = 0;
		virtual bool executeStmt() = 0;
		virtual bool executeQuery() = 0;
		virtual HB_SIZE affectedRows() const = 0;
		virtual bool setAttribute( HB_UINT uiAttribute, PHB_ITEM xValue );
		virtual PHB_ITEM getAttribute( HB_UINT uiAttribute ) const;
		virtual bool isPrepared() const = 0;
		virtual HB_SIZE rowCount() const = 0;
		virtual bool fetchDirect() noexcept = 0;
		virtual bool next(); // Va a la fila siguiente
		virtual bool prev(); // Va a la fila anterior
		virtual bool first(); // Va a la fila primera
		virtual bool last(); // Va a la fila ultima
		virtual bool moveTo( HB_SIZE ulRow ); // Va a la fila indicada
		virtual bool move( HB_LONGLONG llSkip ); // Va a la fila iSkip siguiente o anterior (skip)
		virtual void getBound() const;
		virtual void getArray( PHB_ITEM aRec ) const;
		virtual void getHash( PHB_ITEM hRec ) const;
		virtual void getJson( PHB_ITEM cJson ) const;
		virtual void getAllArray();
		virtual void getAllArray( PHB_ITEM aRec );
		virtual void getAllHash();
		virtual void getAllJson();
		virtual void columnGet( HB_UINT columnIndex = 1 ) const;
		virtual const char *columnName( HB_UINT columnIndex ) const = 0;
		virtual int columnLen( HB_UINT columnIndex ) const = 0;
		virtual int columnNativeType( HB_UINT columnIndex ) const = 0;
		virtual const char *columnType( HB_UINT columnIndex ) const = 0;
		virtual void columnNames() const;
		virtual void columnNames( PHB_ITEM aColNames ) const;
		virtual bool nextRowset() = 0;
		virtual void *gethStmt() const = 0;
		virtual void getString( HB_UINT columnIndex ) const = 0;
		virtual void getInteger( HB_UINT columnIndex ) const = 0;
		virtual void getDouble( HB_UINT columnIndex ) const = 0;
		virtual void getDate( HB_UINT columnIndex ) const = 0;
		virtual void getDateTime( HB_UINT columnIndex ) const = 0;
		virtual void getBool( HB_UINT columnIndex ) const = 0;
		virtual void getBlob( HB_UINT columnIndex ) const = 0;
		// Metodos inline
		inline HB_UINT columnCount() const
		{
			return uiColumnCount;
		}

		inline void setColumnCount( HB_UINT uiColumns = 0 )
		{
			uiColumnCount = uiColumns;
		}

		inline HB_UINT paramCount() const
		{
			return uiParamCount;
		}

		inline void setParamCount( HB_UINT uiParams = 0 )
		{
			uiParamCount = uiParams;
		}

		virtual inline bool bof() const
		{
			return iRowCount == 0 || iCurrentRow == -1;
		}

		virtual inline bool eof() const
		{
			return iRowCount == 0 || iCurrentRow >= iRowCount;
		}

	protected:
		virtual void setBindParam( HB_UINT index ) const = 0;
		virtual void setBindColumn( HB_UINT columnIndex, PHB_ITEM xResult ) const = 0;

	private:
};

class THResultSet : public TXVObject
{
	private:
		PHB_ITEM aData; // Array de arrays que contiene los datos
		PHB_ITEM aColumnNames; // Array de nombres de columnas
		HB_SIZE uiRowCount = 0; // Total de filas
		HB_SIZE uiCurrentRow; // Índice de la fila actual (base 1)
		HB_SIZE uiColumnCount = 0; // Numero de columnas

	public:
		// Constructor y destructor /* crear otro constructor especifico para usar en TStatement sin hacer los hb_itemCopy() */
		THResultSet( PHB_ITEM data, PHB_ITEM columnNames );
		THResultSet();
		virtual ~THResultSet() override;
		// Eliminar constructor de copia y operador de asignación
		THResultSet( const THResultSet & ) = delete;
		THResultSet &operator=( const THResultSet & ) = delete;
		// Métodos de navegación
		virtual bool next(); // Avanza a la siguiente fila
		virtual bool previous(); // Retrocede a la fila anterior
		virtual bool first(); // Va a la primera fila
		virtual bool last(); // Va a la última fila
		virtual bool moveTo( HB_SIZE row ); // Va a una fila específica
		virtual bool move( HB_ISIZ offset ); // Mueve el cursor un número relativo de filas
		// Métodos de estado del cursor
		virtual bool bof() const; // Comprueba si estamos antes de la primera fila
		virtual bool eof() const; // Comprueba si estamos después de la última fila
		// Métodos de acceso a datos
		virtual PHB_ITEM valueByPos( HB_SIZE index ) const; // Obtiene el valor de una columna
		virtual PHB_ITEM valueByName( const char *colName ) const; // Obtiene el valor de una columna

		virtual inline HB_SIZE getCurrentRow() const
		{
			return uiCurrentRow; // Obtiene el número de fila actual
		}

		virtual inline HB_SIZE getRowCount() const
		{
			return uiRowCount; // Obtiene el número total de filas
		}

		virtual inline void setRowCount( HB_SIZE uiNewRowCount = 0 )
		{
			uiRowCount = uiNewRowCount;
		}

		virtual inline void setColumnCount( HB_SIZE uiNewColumnCount = 0 )
		{
			uiColumnCount = uiNewColumnCount;
		}

		inline PHB_ITEM getData() const
		{
			return aData;
		}

		inline PHB_ITEM getColumnNames() const
		{
			return aColumnNames;
		}

	private:
		// Métodos auxiliares
		virtual HB_SIZE findColumnIndex( const char* columnName ) const; // Busca el índice de una columna por nombre
};

//-----------------------------------------------------------------------------
#endif // _HVDBC_HPP
//-----------------------------------------------------------------------------

Espero vuestro apoyo 8)

Re: Presentamos HDBC – La Mejor Conexión a Bases de Datos para Harbour

Posted: Fri Mar 07, 2025 12:28 am
by xmanuel
Marco Augusto wrote: Wed Mar 05, 2025 8:01 pm Saludos
puedo usar MYSQL via ADO
HDBC con acceso nativo a MySQL/MaríaDb será mucho más rápida que "MYSQL vía ADO" por lo que no renta usar ADO.

Saludos

Re: Presentamos HDBC – La Mejor Conexión a Bases de Datos para Harbour

Posted: Fri Mar 07, 2025 12:42 am
by xmanuel
Este ejemplo que pongo a continuación es una importación de la tabla "test.dbf" a PostgreSQL tarda menos 40 milisegundos en local:

Code: Select all | Expand

///////////////////////////////////////////////////////////////////////////////
// Proyecto: hdbc
// Fichero: test008.prg
// Autor: Manu Exposito
// Fecha: 
// Descripcion: Traspasa test.dbf de los ejemplos de Harbour a SQL.
//              Si no existe la bases de datos la crea.
//              Si no existe la tabla test la crea.
//              Uso de bindParam
///////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------------------

#include "hdbc.ch" 
#include "postgresql_connect.ch" 

#define ID_CARGA	500

//------------------------------------------------------------------------------
// Programa principal

procedure main()

    local oDb, e
    local cCreaTable 

    TEXT INTO cCreaTable
    CREATE TABLE IF NOT EXISTS test
    (
        id          SERIAL,
        first       VARCHAR( 20 ),
        last        VARCHAR( 20 ),
        street      VARCHAR( 30 ),
        city        VARCHAR( 30 ),
        state       VARCHAR( 2 ),
        zip         VARCHAR( 10 ),
        hiredate    DATE,
        married     BOOLEAN,
        age         INTEGER,
        salary      DECIMAL( 9, 2 ),
        notes       VARCHAR( 70 ),
        PRIMARY KEY ( id )
    )

    ENDTEXT
 
    cls

    msg( "Traspaso de datos..." )

    try
        oDb := THDbc():new( _DRIVER_ )

        oDb:connect( _CONN_STRING_ )        
        oDb:exec( cCreaTable )
        
        traspasa( oDb )

    catch  e
        eval( errorBlock(), e )
    finally
        oDb:disconnect()
        msg( "Esto es todo!!!" )
    end	
return

//------------------------------------------------------------------------------
// Usa sentencias preparadas en el lado del servidor y transacciones.

static procedure traspasa( oDb )

    local n := 0, nSec
    local oInsert
    local first, last, street, city, state, zip, hiredate, married, age, salary, notes

    local cSentencia := "INSERT INTO test ( first, last, street, city, state, zip, "  + ;
        "hiredate, married, age, salary, notes ) " + ;
        "VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11 );"

    if file( "test.dbf" )
		
        use test new
		
        oInsert := oDb:prepareStatement( cSentencia ) // Crea el objeto y prepara la sentencia

        // Vincula las variables harbour con cada una de las "?" por su posicion
        oInsert:bindParam(  1, @first  )
        oInsert:bindParam(  2, @last  )
        oInsert:bindParam(  3, @street )
        oInsert:bindParam(  4, @city )
        oInsert:bindParam(  5, @state )
        oInsert:bindParam(  6, @zip )
        oInsert:bindParam(  7, @hiredate )
        oInsert:bindParam(  8, @married )
        oInsert:bindParam(  9, @age )
        oInsert:bindParam( 10, @salary )
        oInsert:bindParam( 11, @notes )

        nSec := hb_milliSeconds()
	
        oDb:beginTrans()
		
        while n < ID_CARGA	
	
            while test->( !eof() )
                first    := test->first
                last     := test->last
                street   := test->street
                city     := test->city
                state    := test->state
                zip      := test->zip
                hiredate := test->hiredate 
                married  := test->married
                age      := test->age
                salary   := test->salary
                notes    := test->notes
		
                oInsert:execute()
                
                ++n

                test->( dbskip( 1 ) )
            end
	
            test->( DbGoTop() )
        end

        oDb:commit()		

        nSec := hb_milliSeconds() - nSec 

        msg( "Se han pasado " + Hb_NToS( n ) + " registros en " + Hb_NToS( nSec ) + " milisegundos", "Uso de bindParam" )
    else
        msg( "Fichero test.dbf no existe" )
    endif

return

//------------------------------------------------------------------------------


Re: Presentamos HDBC – La Mejor Conexión a Bases de Datos para Harbour

Posted: Fri Mar 07, 2025 12:46 am
by xmanuel
Como podéis ver usa dos técnicas muy importantes en los lenguajes modernos:
- Las transacciones que garantizan que el proceso ha finalizado correctamente.
- Las sentencias preparadas en el lado del servidor que evitan enviar las sentencias como tramas en la red y evitan inyección de código lo que además de velocidad proporcionan seguridad total.