Native access to Sqlite3

Native access to Sqlite3

Postby alvaro533 » Wed Jun 28, 2023 1:59 pm

Hello,

I had an old program that used an sqlite3 database. To achieve this, I used an OBDC connector that had to be installed on each computer in order to use the program. This connector, "sqliteodbc.exe," comes from the website:

http://www.ch-werner.de/sqliteodbc/

Some clients were reluctant to install third-party software on their computers. Therefore, in an attempt to access sqlite3 databases natively, I have created two classes, which I am attaching along with a small example of usage. However, I haven't figured out a good way to display the records in xbrowse. I convert them to an Array, and it works fine, but it's not the cleanest solution. If anyone has any ideas on how to improve this, I would appreciate it.

You need to link "hbsqlit3.hbc," which comes with Harbour, and have "hbsqlit3.ch" accessible, which also comes with Harbour.

The sqlite functions can be found here:

https://www.sqlite.org/c3ref/funclist.html

test.prg
Code: Select all  Expand view  RUN
#include "fivewin.ch"
#include "hbsqlit3.ch"

static oWnd

function test()

    local oBar
    local aArray
    local oCn

    local cCreate
   
    cCreate := 'CREATE TABLE t1( '+;
        'id INTEGER PRIMARY KEY AUTOINCREMENT, '+ ;
        'name TEXT, '+ ;
        'age INTEGER '+ ;
        ') ;'

    cCreate += "CREATE UNIQUE INDEX id on t1 (id); "

    cCreate += "BEGIN TRANSACTION;" + ;
        "INSERT INTO t1( name, age ) VALUES( 'Bob', 52 );" + ;
        "INSERT INTO t1( name, age ) VALUES( 'Fred', 40 );" + ;
        "INSERT INTO t1( name, age ) VALUES( 'Sasha', 25 );" + ;
        "INSERT INTO t1( name, age ) VALUES( 'Ivet', 28 );" + ;
        "COMMIT;"
   
   
    oCn := aq_Sqlite():new( "test.db" , cCreate )
    if oCn == nil
        return nil
    endif

    // oCn:executeStatement( 'ALTER TABLE t1 ADD address TEXT' )
   

    define Window oWnd MDI title "TEST"

    DEFINE BUTTONBAR oBar 3D OF oWnd size 40,60  2007
    define button of obar name ""  Prompt "Test1"+CRLF action ( test1() , oWnd:Tile(.f.) )
   
    oWnd:bKeyDown := { | nKey | iif( nKey==VK_ESCAPE , oWnd:end() , nil ) }

    activate window oWnd on init test1() ;
   


return nil



// ------------------------------------------------------------------------------------ //
static function test1()
    local oWnd2
    local oBrw
    local oBar
    local cSeek
    local aData
    local nRowSel
   
        define Window oWnd2 MDICHILD of oWnd title "Test1"

    DEFINE BUTTONBAR oBar 3D OF oWnd2 size 40,60  2007
    define button of obar name ""  Prompt "Add"+CRLF action  edit(oBrw , .t. )  
    define button of obar name ""  Prompt "Edit"+CRLF action  edit(oBrw )
    define button of obar name ""  Prompt "Del"+CRLF action  del_record(oBrw )  


    oWnd2:bKeyDown := { | nKey | iif( nKey==VK_ESCAPE , oWnd2:end() , nil ) }
    oWnd2:bGotFocus := { | | nRowSel := oBrw:nArrayAt ,;
        cSeek:= oBrw:cSeek ,oBrw:seek(''), oBrw:SetArray( requery(oBrw) ) , oBrw:seek(cSeek) ,;
        oBrw:Bookmark(nRowSel) , oBrw:refresh() }

    activate window oWnd2 on init oBrw:=create_browse(oWnd2,aData) valid (  .t. )
   


return nil


// ---------------------------------------------------------------------------------------//
static function requery(oBrw)
    local aData
   
    aData := oCn():getarray( "SELECT id,name FROM t1 " )

    if empty(aData)
        aData := array(len(oBrw:aCols))
        aFill(aData,nil)
        aData := {aData}
    endif

   

return aData

// ---------------------------------------------------------------------------------------//
static function create_browse(oWnd2,aData)
    local oCol
    local bdclick
    local oBrw


   
    oBrw := TXBrowse():New( oWnd2 )

    bdclick:={ || edit(oBrw) }

    oBrw:nMarqueeStyle       := 5
    oBrw:nColDividerStyle    := LINESTYLE_BLACK
    oBrw:nRowDividerStyle    := LINESTYLE_BLACK
    oBrw:lColDividerComplete := .t.
    oBrw:nHeaderLines        := 1
    oBrw:nDataLines          := 1
    oBrw:lfooter          := .t.
    oBrw:nfooterLines        := 2
    oBrw:L2007:=.t.
    oBrw:lAllowRowSizing:=.f.

   
    oCol := oBrw:AddCol()  
    oCol:bStrData := { || oBrw:aArrayData[  oBrw:nArrayAt , 1  ]  }
    oCol:cHeader  := "Recn"
    ocol:nDataStrAlign:=2
    oCol:nHeadStrAlign:=2
    oCol:nWidth:=60
    oCol:blDClickData:= bdclick

    oCol := oBrw:AddCol()  
    oCol:bStrData := { || oBrw:aArrayData[  oBrw:nArrayAt , 2  ]  }
    oCol:cHeader  := "name"
    ocol:nDataStrAlign:=0
    oCol:nHeadStrAlign:=2
    oCol:nWidth:=250
    oCol:blDClickData:= bdclick

   
    if empty(aData)
        aData := array(len(oBrw:aCols))
        AFill(aData,nil)
        aData := {aData}
    endif


    oBrw:SetArray(aData)

   
    oBrw:lseekbar := .t.
    oBrw:lSeekWild := .t.
    oBrw:lIncrFilter := .t.
    oBrw:cFilterFld := 'name'
    oBrw:lautosort  := .t.
    oBrw:bClrEdits := { || { CLR_BLACK, CLR_YELLOW } }

    oBrw:oFilterCol:=oBrw:aCols[2]
     

    oBrw:CreateFromCode()
    oWnd2:oClient := oBrw
    oBrw:setfocus()
    oBrw:SetArray( requery(oBrw) )
    oBrw:refresh()

return oBrw


// ---------------------------------------------------------------------------------------//
static function del_record(oBrw)
    local cSql
    local cSeek
    local nRow

    if !msgyesno('Delete record?'+CRLF+CRLF+oBrw:aArrayData[  oBrw:nArrayAt , 2  ])
        return nil
    endif


    nRow := oBrw:nArrayAt
    cSql := "DELETE FROM t1 WHERE id='"+hb_ValToStr( oBrw:aArrayData[oBrw:nArrayAt,1] )+"' "

    oCn():executeStatement( cSql )
    cSeek:= oBrw:cSeek
    oBrw:seek('')
    oBrw:SetArray( requery(oBrw) )
    oBrw:seek(cSeek)
    oBrw:KeyNo(nRow-1)

return nil

// ---------------------------------------------------------------------------------------//
static function edit(oBrw , lAppend )
   
    local nBookMark
    local cSeek
    local oEdit
    local oDlg
    local oFont,oFont2
    local lSave := .f.

    default lAppend := .f.

   

    oEdit := aq_SqliteDataRow():new( 't1','id',oBrw:aArrayData[  oBrw:nArrayAt , 1  ])

    if lAppend
        oEdit:blank()
    else
        oEdit:load()
    endif
   
    nBookMark := oBrw:nArrayAt
    oEdit:name := PadR( oEdit:name , 30)

    DEFINE FONT oFont NAME "Arial" SIZE 0, 18 BOLD
    DEFINE FONT oFont2 NAME "Arial" SIZE 0, 16 BOLD

    define dialog oDlg  size 600,400 pixel Title "Test: "+iif(lAppend,'Adding','Recn: '+str(nBookMark) )

    @ 20 , 10 say "Name:" size 200 , 20 pixel of oDlg  font oFont
    @ 20 , 40 get oEdit:name size 150 , 15 pixel of oDlg  font oFont2
    @ 50 , 10 say "Age:" size 200 , 20 pixel of oDlg  font oFont
    @ 50 , 40 get oEdit:age picture '999' size 150 , 15  pixel of oDlg  font oFont2
    @ 180 , 200 button "Cancel" size 40 , 10 pixel of oDlg  font oFont action oDlg:end()
    @ 180 , 250 button "Save" size 40 , 10 pixel of oDlg  font oFont action (lSave:=.t.,oDlg:end())
   
    activate dialog odlg centered ;
        valid( iif( oEdit:modified() , iif(lsave, .t., msgyesno("Exit without saving?") ) , .t. ) )

 
    if lSave
        oEdit:name := alltrim(oEdit:name)
             
        if lAppend
            nBookMark := oEdit:insert()
            oBrw:seek('')
            oBrw:SetArray( requery(oBrw) )
            oBrw:Bookmark(nBookMark)
        else
            if oEdit:modified()
                oEdit:save()
                cSeek:= oBrw:cSeek
                oBrw:seek('')
                oBrw:SetArray( requery(oBrw) )
                oBrw:seek(cSeek)
                oBrw:Bookmark := nBookMark
            endif
           
        endif

        oBrw:refresh()
               
    endif

    oEdit:end()

return nil

 


aq_Sqlite.prg
Code: Select all  Expand view  RUN
#include "fivewin.ch"
#include "hbsqlit3.ch"


class aq_Sqlite

    DATA  db
    DATA  dbfile
 
    METHOD New( dbfile , cCreate )
    METHOD getArray(cSql)
    METHOD getFields(cTable)
    METHOD getTypes(cTable)
    METHOD executeStatement(cSql)
       
    METHOD End()
 
 
ENDCLASS
 
 
// ----------------------------------------------------------------------------- //
METHOD New( dbfile , cCreate ) CLASS aq_Sqlite
    default dbfile:= 'test.db'
    default cCreate := 'CREATE TABLE t1( '+;
        'id INTEGER PRIMARY KEY AUTOINCREMENT, '+ ;
        'name TEXT '+ ;
        ')'
   
    ::dbfile := dbfile
   
    if !file( dbfile )
        if !msgyesno("File does not exist, create?"+CRLF+CRLF+dbfile)
            return nil
        endif
        ::db := sqlite3_open( dbfile , .t. )
        sqlite3_exec( ::db, "PRAGMA auto_vacuum=0" )
        sqlite3_exec( ::db, "PRAGMA page_size=4096" )
        sqlite3_exec( ::db, cCreate )
       

    else
        ::db := sqlite3_open( dbfile  )            
    endif

    oCn(Self)

RETURN Self
 
// ----------------------------------------------------------------------------- //
METHOD executeStatement(  cSql ) CLASS aq_Sqlite
    local stmt
    local result

    result := sqlite3_exec( ::db, cSql  )

    if result != SQLITE_OK
        msginfo("Error: "+hb_sqlite3_errstr_short(result)+CRLF+CRLF+cSql)
    endif
   

return nil

// ----------------------------------------------------------------------------- //
METHOD getArray(  cSql ) CLASS aq_Sqlite
    local aArray:= {}
    local aArray1
    local stmt
    local nFor
    local nCol
    local aFields := {}
    local cField

    cursorwait()

    stmt := sqlite3_prepare( ::db, cSql  )
    nCol := sqlite3_column_count(stmt)
   

    for nFor :=1 to nCol
        cField := sqlite3_column_decltype( stmt, nFor )
        cField := standard_cField( cField )
        aadd(aFields,cField)
    next nFor

    DO WHILE sqlite3_step( stmt ) == SQLITE_ROW
        aArray1:= {}
        for nFor :=1 to nCol
            do case
                case aFields[nFor] == 'INTEGER'
                    aadd(aArray1, sqlite3_column_int(stmt, nFor) )
                case aFields[nFor] == 'REAL'
                    aadd(aArray1, sqlite3_column_double(stmt, nFor) )
                case aFields[nFor] == 'TEXT'
                    aadd(aArray1, sqlite3_column_text(stmt, nFor) )
                case aFields[nFor] == 'BLOB'
                    aadd(aArray1, sqlite3_column_blob(stmt, nFor) )
                    otherwise
                    aadd(aArray1, 'error' )
            endcase
           
        next nFor
        aadd( aArray , aArray1 )
    enddo
   
    sqlite3_clear_bindings( stmt )
    sqlite3_finalize( stmt )

    cursorarrow()

return aArray

// ----------------------------------------------------------------------------- //
METHOD getFields(  cTable ) CLASS aq_Sqlite
    local stmt
    local nFor
    local nCol
    local cField
    local aFields := {}

    stmt := sqlite3_prepare( ::db, 'SELECT * FROM '+cTable+'  LIMIT 1'  )
    nCol := sqlite3_column_count(stmt)
   
    for nFor :=1 to nCol
        cField := upper( sqlite3_column_name( stmt, nFor ) )
        aadd(aFields,cField)
    next nFor
   
    sqlite3_clear_bindings( stmt )
    sqlite3_finalize( stmt )

return aFields

// ----------------------------------------------------------------------------- //
METHOD getTypes(  cTable ) CLASS aq_Sqlite
    local stmt
    local nFor
    local nCol
    local cField
    local aFields := {}

    stmt := sqlite3_prepare( ::db, 'SELECT * FROM '+cTable+'  LIMIT 1'  )
    nCol := sqlite3_column_count(stmt)
   

    for nFor :=1 to nCol
        cField := upper( sqlite3_column_decltype( stmt, nFor ) )
        aadd(aFields,{ cField , standard_cField( cField) } )
    next nFor

    sqlite3_clear_bindings( stmt )
    sqlite3_finalize( stmt )

return aFields

// ----------------------------------------------------------------------------- //
METHOD End(  ) CLASS aq_Sqlite
 
return nil

// ----------------------------------------------------------------------------- //
static function standard_cField( cField )

    cField := alltrim(upper( cField ))

    if 'CHAR'$cField .or. "TEXT"$cField
        cField := "TEXT"
    elseif substr( cField , 1, 3 ) == 'INT'
        cField := "INTEGER"
    elseif cField == 'FLOAT' .or. cField == 'REAL'
        cField := "REAL"
    elseif substr( cField , 1, 3 ) == 'NUM'
        cField := "REAL"
    elseif 'BLOB'$cField
        cField := "BLOB"
    else
        msginfo('Error standard_cField: '+cField)
    endif

return cField

// ----------------------------------------------------------------------------- //
function oCn(oCn)
    static oConn
   
    if oConn == nil
        oConn:= oCn
    endif
   
return oConn
 

 


aq_SqliteDataRow.prg
Code: Select all  Expand view  RUN
#include "fivewin.ch"
#include "hbsqlit3.ch"


class aq_SqliteDataRow

    DATA  cTable
    DATA  cIndex
    DATA  row
    DATA  aFields
    DATA  aTypes
    DATA  aValues
    DATA  aValues_ini
 
    METHOD New(cTable, cIndex , row  )

    METHOD blank()
    METHOD load()
    METHOD save()
    METHOD insert()
    METHOD modified()
       
    METHOD End()
 
    ERROR HANDLER OnError( uParam1 )
 
ENDCLASS
 
 
// ----------------------------------------------------------------------------- //
METHOD New( cTable, cIndex , row ) CLASS aq_SqliteDataRow
    default row := 0

    ::cTable := cTable
    ::cIndex := cIndex
    ::row := row

    ::aFields := oCn():getFields(cTable)
    ::aTypes := oCn():getTypes(cTable)

RETURN Self
 
// ----------------------------------------------------------------------------- //
METHOD blank( ) CLASS aq_SqliteDataRow
    local nFor
    local xValue
    local cad
   
    ::aValues := { 0 }
    for nFor := 2 to len( ::aFields )
        xValue := nil
        if ::aTypes[nFor,2]=='INTEGER' .or. ::aTypes[nFor,2]=='REAL'
            xValue := 0
        elseif ::aTypes[nFor,2]=='BLOB'
            xValue := ''
        elseif 'CHAR'$::aTypes[nFor,1] .and. '('$::aTypes[nFor,1]
            cad := SubStr( ::aTypes[nFor,1] , at('(', ::aTypes[nFor,1] )+1 )
            cad := SubStr( cad , 1 , at(')', cad) - 1 )
            xValue := Replicate(' ',val( cad )  )
        elseif 'TEXT'==::aTypes[nFor,2]
            xValue:= space( 30 )
        else
            msginfo('Error blank: '+::aTypes[nFor,1] )
            xValue:= space( 30 )
        endif

        aadd( ::aValues ,  xValue )
    next nFor

    ::aValues_ini := AClone( ::aValues )

   
return nil

// ----------------------------------------------------------------------------- //
METHOD load( ) CLASS aq_SqliteDataRow

    ::aValues := oCn():getArray( "SELECT * FROM "+::cTable+" WHERE "+::cIndex+"='"+ ;
        alltrim(hb_ValToStr(::row))+"' LIMIT 1")[1]
   
    ::aValues_ini := AClone( ::aValues )

return nil

// ----------------------------------------------------------------------------- //
METHOD save( ) CLASS aq_SqliteDataRow
    local cSql
    local cad := ''
    local nFor

    if ::modified()

        for Nfor :=1 to len(::aValues)
            if !( ::aValues[nFor] == ::aValues_ini[nfor] )
                cad += ::aFields[nFor]+"='"+alltrim(hb_ValToStr(::aValues[nFor]))+"',"
            endif
        next nFor
        cad:= subs(cad,1,len(cad)-1)
        cSql := 'UPDATE '+::cTable+' SET '+cad+' WHERE '+::cIndex+"='"+ ;
            alltrim(hb_ValToStr(::row))+"'"
        oCn():executeStatement( cSql )
    endif
   
return nil

// ----------------------------------------------------------------------------- //
METHOD insert( ) CLASS aq_SqliteDataRow
    local cSql
    local fields := ''
    local values := ''
    local nFor
    local nlast := 0

        for Nfor :=2 to len(::aValues)
            fields += ::aFields[nFor]+','
            values += "'"+alltrim(hb_ValToStr(::aValues[nFor]))+"',"
        next nFor
        fields:= subs(fields,1,len(fields)-1)
        values:= subs(values,1,len(values)-1)
        cSql := 'INSERT INTO '+::cTable+' ('+fields+') VALUES ('+values+') '
        oCn():executeStatement( cSql )

        nlast := sqlite3_last_insert_rowid( oCn():db )
   
return nlast

// ----------------------------------------------------------------------------- //
METHOD modified( ) CLASS aq_SqliteDataRow
    local nFor

    for Nfor :=1 to len(::aValues)
        if valtype( ::aValues[nFor]) =='C'
            ::aValues[nFor] := alltrim( ::aValues[nFor] )
        endif
        if !( ::aValues[nFor] == ::aValues_ini[nfor] )
            return .t.
        endif
    next nFor
return .f.



// ----------------------------------------------------------------------------- //
METHOD End(  ) CLASS aq_SqliteDataRow
    ::aFields := nil
    ::aValues := nil
    ::aValues_ini := nil
   
return nil


// ----------------------------------------------------------------------------- //
METHOD OnError( uParam1 ) CLASS aq_SqliteDataRow
    local cMsg   := __GetMessage()
    local nError := If( SubStr( cMsg, 1, 1 ) == "_", 1005, 1004 )
    local nField

    cMsg = Upper( cMsg )

 
    if SubStr( cMsg, 1, 1 ) == "_"
        if( ( nField := AScan( ::aFields,;
                { | cField | SubStr( cMsg, 2 ) == ;
                RTrim( SubStr( cField, 1, 25 ) ) } ) ) != 0 )  // era 9 en lugar de 25
            ::aValues[nField] :=  uParam1
        else
            _ClsSetError( _GenError( nError, ::ClassName(), SubStr( cMsg, 2 ) ) )
        endif
    else
        if( ( nField := AScan( ::aFields,;
                { | cField | cMsg == ;
                RTrim( SubStr( cField, 1, 25 ) ) } ) ) != 0 )   // era 9 en lugar de 25
            return ::aValues[nField]
        else
            _ClsSetError( _GenError( nError, ::ClassName(), cMsg ) )
        endif
    endif

 
    return nil

   


Best regards.

Alvaro
alvaro533
 
Posts: 206
Joined: Sat Apr 19, 2008 10:28 pm
Location: Madrid, España

Re: Native access to Sqlite3

Postby nageswaragunupudi » Wed Jun 28, 2023 6:56 pm

I haven't figured out a good way to display the records in xbrowse. I convert them to an Array, and it works fine, but it's not the cleanest solution

This is the best approach.

For information: Soon FWH is planning to come out with a native sqlite3 class included in the FWH libs
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10655
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Native access to Sqlite3

Postby carlos vargas » Wed Jun 28, 2023 8:29 pm

Please, with sqlcipher
Salu2
Carlos Vargas
Desde Managua, Nicaragua (CA)
User avatar
carlos vargas
 
Posts: 1721
Joined: Tue Oct 11, 2005 5:01 pm
Location: Nicaragua

Re: Native access to Sqlite3

Postby alvaro533 » Fri Jun 30, 2023 8:21 pm

Thank you Mr. Rao. Any estimate on the release date?

Regards,

AQ
alvaro533
 
Posts: 206
Joined: Sat Apr 19, 2008 10:28 pm
Location: Madrid, España

Re: Native access to Sqlite3

Postby kajot » Sat Jul 01, 2023 1:00 pm

where is hbsqlit3.ch
best regards
kajot
best regards
kajot
User avatar
kajot
 
Posts: 339
Joined: Thu Nov 02, 2006 6:53 pm
Location: Poland

Re: Native access to Sqlite3

Postby alvaro533 » Sat Jul 01, 2023 1:09 pm

Hi,

In my installation is in:

\harbour\contrib\hbsqlit3\hbsqlit3.ch

But I copy it here anyway.

Regards,

hbsqlit3.ch
Code: Select all  Expand view  RUN
/*
 * SQLite3 library low level (client api) interface code
 *
 * Copyright 2007 P.Chornyj <myorg63@mail.ru>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file LICENSE.txt.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
 *
 * As a special exception, the Harbour Project gives permission for
 * additional uses of the text contained in its release of Harbour.
 *
 * The exception is that, if you link the Harbour libraries with other
 * files to produce an executable, this does not by itself cause the
 * resulting executable to be covered by the GNU General Public License.
 * Your use of that executable is in no way restricted on account of
 * linking the Harbour library code into it.
 *
 * This exception does not however invalidate any other reasons why
 * the executable file might be covered by the GNU General Public License.
 *
 * This exception applies only to the code released by the Harbour
 * Project under the name Harbour.  If you copy code from other
 * Harbour Project or Free Software Foundation releases into a copy of
 * Harbour, as the General Public License permits, the exception does
 * not apply to the code that you add in this way.  To avoid misleading
 * anyone as to the status of such modified files, you must delete
 * this exception notice from them.
 *
 * If you write modifications of your own for Harbour, it is your choice
 * whether to permit this exception to apply to your modifications.
 * If you do not wish that, delete this exception notice.
 *
 */


#ifndef HBSQLIT3_CH_
#define HBSQLIT3_CH_

#xtranslate DB_IS_OPEN( <db> )         => ( ! Empty( <db> ) )
#xtranslate STMT_IS_PREPARED( <stmt> ) => ( ! Empty( <stmt> ) )

/* Fundamental Datatypes */
#define SQLITE_INTEGER                     1
#define SQLITE_FLOAT                       2
#define SQLITE_TEXT                        3
#define SQLITE3_TEXT                       SQLITE_TEXT
#define SQLITE_BLOB                        4
#define SQLITE_NULL                        5

#define SQLITE_OK                          0   /* Successful result */
/* Beginning-of-Error-Codes */
#define SQLITE_ERROR                       1   /* SQL error or missing database */
#define SQLITE_INTERNAL                    2   /* NOT USED. Internal logic error in SQLite */
#define SQLITE_PERM                        3   /* Access permission denied */
#define SQLITE_ABORT                       4   /* Callback routine requested an abort */
#define SQLITE_BUSY                        5   /* The database file is locked */
#define SQLITE_LOCKED                      6   /* A table in the database is locked */
#define SQLITE_NOMEM                       7   /* A malloc() failed */
#define SQLITE_READONLY                    8   /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT                   9   /* Operation terminated by sqlite3_interrupt()*/
#define SQLITE_IOERR                       10  /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT                     11  /* The database disk image is malformed */
#define SQLITE_NOTFOUND                    12  /* NOT USED. Table or record not found */
#define SQLITE_FULL                        13  /* Insertion failed because database is full */
#define SQLITE_CANTOPEN                    14  /* Unable to open the database file */
#define SQLITE_PROTOCOL                    15  /* NOT USED. Database lock protocol error */
#define SQLITE_EMPTY                       16  /* Database is empty */
#define SQLITE_SCHEMA                      17  /* The database schema changed */
#define SQLITE_TOOBIG                      18  /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT                  19  /* Abort due to constraint violation */
#define SQLITE_MISMATCH                    20  /* Data type mismatch */
#define SQLITE_MISUSE                      21  /* Library used incorrectly */
#define SQLITE_NOLFS                       22  /* Uses OS features not supported on host */
#define SQLITE_AUTH                        23  /* Authorization denied */
#define SQLITE_FORMAT                      24  /* Auxiliary database format error */
#define SQLITE_RANGE                       25  /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB                      26  /* File opened that is not a database file */
#define SQLITE_ROW                         100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE                        101 /* sqlite3_step() has finished executing */
/* End-of-Error-Codes */

/* Combination of the following bit values are used
   as the third argument to the sqlite3_open_v2() interface */

#define SQLITE_OPEN_READONLY               1
#define SQLITE_OPEN_READWRITE              2
#define SQLITE_OPEN_CREATE                 4
#define SQLITE_OPEN_DELETEONCLOSE          8
#define SQLITE_OPEN_EXCLUSIVE              16
#define SQLITE_OPEN_MAIN_DB                256
#define SQLITE_OPEN_TEMP_DB                512
#define SQLITE_OPEN_TRANSIENT_DB           1024
#define SQLITE_OPEN_MAIN_JOURNAL           2048
#define SQLITE_OPEN_TEMP_JOURNAL           4096
#define SQLITE_OPEN_SUBJOURNAL             8192
#define SQLITE_OPEN_MASTER_JOURNAL         16384

/* Status Parameters for prepared statements */
#define SQLITE_STMTSTATUS_FULLSCAN_STEP    1
#define SQLITE_STMTSTATUS_SORT             2

/* Authorizer Action Codes */
#define SQLITE_CREATE_INDEX                1   /* Index Name      Table Name      */
#define SQLITE_CREATE_TABLE                2   /* Table Name      NULL            */
#define SQLITE_CREATE_TEMP_INDEX           3   /* Index Name      Table Name      */
#define SQLITE_CREATE_TEMP_TABLE           4   /* Table Name      NULL            */
#define SQLITE_CREATE_TEMP_TRIGGER         5   /* Trigger Name    Table Name      */
#define SQLITE_CREATE_TEMP_VIEW            6   /* View Name       NULL            */
#define SQLITE_CREATE_TRIGGER              7   /* Trigger Name    Table Name      */
#define SQLITE_CREATE_VIEW                 8   /* View Name       NULL            */
#define SQLITE_DELETE                      9   /* Table Name      NULL            */
#define SQLITE_DROP_INDEX                  10  /* Index Name      Table Name      */
#define SQLITE_DROP_TABLE                  11  /* Table Name      NULL            */
#define SQLITE_DROP_TEMP_INDEX             12  /* Index Name      Table Name      */
#define SQLITE_DROP_TEMP_TABLE             13  /* Table Name      NULL            */
#define SQLITE_DROP_TEMP_TRIGGER           14  /* Trigger Name    Table Name      */
#define SQLITE_DROP_TEMP_VIEW              15  /* View Name       NULL            */
#define SQLITE_DROP_TRIGGER                16  /* Trigger Name    Table Name      */
#define SQLITE_DROP_VIEW                   17  /* View Name       NULL            */
#define SQLITE_INSERT                      18  /* Table Name      NULL            */
#define SQLITE_PRAGMA                      19  /* Pragma Name     1st arg or NULL */
#define SQLITE_READ                        20  /* Table Name      Column Name     */
#define SQLITE_SELECT                      21  /* NULL            NULL            */
#define SQLITE_TRANSACTION                 22  /* Operation       NULL            */
#define SQLITE_UPDATE                      23  /* Table Name      Column Name     */
#define SQLITE_ATTACH                      24  /* Filename        NULL            */
#define SQLITE_DETACH                      25  /* Database Name   NULL            */
#define SQLITE_ALTER_TABLE                 26  /* Database Name   Table Name      */
#define SQLITE_REINDEX                     27  /* Index Name      NULL            */
#define SQLITE_ANALYZE                     28  /* Table Name      NULL            */
#define SQLITE_CREATE_VTABLE               29  /* Table Name      Module Name     */
#define SQLITE_DROP_VTABLE                 30  /* Table Name      Module Name     */
#define SQLITE_FUNCTION                    31  /* NULL            Function Name   */
#define SQLITE_SAVEPOINT                   32  /* Operation       Savepoint Name  */

/* Authorizer Return Codes */
#define SQLITE_DENY                        1   /* Abort the SQL statement with an error */
#define SQLITE_IGNORE                      2   /* Don't allow access, but don't generate an error */

/* Status Parameters */
#define SQLITE_STATUS_MEMORY_USED          0
#define SQLITE_STATUS_PAGECACHE_USED       1
#define SQLITE_STATUS_PAGECACHE_OVERFLOW   2
#define SQLITE_STATUS_SCRATCH_USED         3
#define SQLITE_STATUS_SCRATCH_OVERFLOW     4
#define SQLITE_STATUS_MALLOC_SIZE          5
#define SQLITE_STATUS_PARSER_STACK         6
#define SQLITE_STATUS_PAGECACHE_SIZE       7
#define SQLITE_STATUS_SCRATCH_SIZE         8

/* Status Parameters for database connections */
#define SQLITE_DBSTATUS_LOOKASIDE_USED     0

/* Run-Time Limit Categories */
#define SQLITE_LIMIT_LENGTH                0
#define SQLITE_LIMIT_SQL_LENGTH            1
#define SQLITE_LIMIT_COLUMN                2
#define SQLITE_LIMIT_EXPR_DEPTH            3
#define SQLITE_LIMIT_COMPOUND_SELECT       4
#define SQLITE_LIMIT_VDBE_OP               5
#define SQLITE_LIMIT_FUNCTION_ARG          6
#define SQLITE_LIMIT_ATTACHED              7
#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH   8
#define SQLITE_LIMIT_VARIABLE_NUMBER       9
#define SQLITE_LIMIT_TRIGGER_DEPTH         10

#endif
alvaro533
 
Posts: 206
Joined: Sat Apr 19, 2008 10:28 pm
Location: Madrid, España

Re: Native access to Sqlite3

Postby Antonio Linares » Sat Jul 01, 2023 1:11 pm

regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42122
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Native access to Sqlite3

Postby José Luis Sánchez » Tue Sep 05, 2023 6:53 am

Alvaro, me puedes contactar por email en correo.alanit arroba gmail punto com por favor ? Me interesa mucho colaborar contigo en este tema.

Mr. Rao, when will the Sqlite class for FWH be available ?

Regards,
José Luis
User avatar
José Luis Sánchez
 
Posts: 556
Joined: Thu Oct 13, 2005 9:23 am
Location: Novelda - Alicante - España

Re: Native access to Sqlite3

Postby albeiroval » Fri Sep 08, 2023 1:55 pm

carlos vargas wrote:Please, with sqlcipher


+1
Saludos,
Regards,

Albeiro Valencia
www.avcsistemas.com
User avatar
albeiroval
 
Posts: 379
Joined: Tue Oct 16, 2007 5:51 pm
Location: Barquisimeto - Venezuela

Re: Native access to Sqlite3

Postby xmanuel » Mon Oct 02, 2023 3:41 pm

Desgraciadamente en SQLite no hay recordset navegables.
Solo hay la posibilidad de avanzar en el resultado de un SELECT por lo que siempre hay que crear un array o un hash para poder navegar en todas las direcciones.

Recientemente he hecho una pequeña LIB para acceder a SQLite muy sencilla con las siguientes características:

1) Está hecha en C++ al 100x100 para usar como clase desde Harbour. (Integración de Harbour y Lenguaje C++)
2) Muy compacta y robusta
3) Todo el código fuente de las clases C++ y Harbour.
4) Varios ejemplos
5) Uso libre
______________________________________________________________________________
Sevilla - Andalucía
xmanuel
 
Posts: 762
Joined: Sun Jun 15, 2008 7:47 pm
Location: Sevilla


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 32 guests