2009-03-30 11:30 UTC+0200 Petr Chornyj (myorg63 at mail.ru)

* contrib/hbsqlit3/hbsqlit3.ch
   * contrib/hbsqlit3/hbsqlit3.c
      * Added support for sqlite_exec() callback. 
         Now the 3rd parameter is an optional callback that is invoked
         once for each row of any query results.
      * Now we can pass name of logfile as third parameter of
         sqlite3_trace(), sqlite3_profile(). 
      + Added sqlite3_set_authorizer() - 
         Compile-Time Authorization Callbacks.
      + Added sqlite3_busy_handler() - 
         A Callback To Handle SQLITE_BUSY Errors.
      + Added sqlite3_progress_handler() - Query Progress Callbacks.
      + Added sqlite3_commit_hook(), sqlite3_rollback_hook() -
         Commit And Rollback Notification Callbacks
      + Added sqlite3_backup_*() API for backups purposes.
      + Added sqlite3_initialize(), sqlite3_shutdown(), sqlite3_interrupt(),
         sqlite3_status(), sqlite3_db_status(), sqlite3_stmt_status(), 
         sqlite3_sql(), sqlite3_extended_errcode(), sqlite3_threadsafe(),
         sqlite3_memory_used(), sqlite3_memory_highwater(). 
      ! Fixed sqlite3_table_column_metadata().
      - Temporary disabled sqlite3_db_handle().
      * Minor changes, cleanup and formating. 
   + contrib/hbsqlit3/tests/authorizer.prg 
   + contrib/hbsqlit3/tests/backup.prg 
   + contrib/hbsqlit3/tests/hooks.prg 
      + Added for demonstration of new possibilities.
   + contrib/hbsqlit3/tests/metadata.prg 
      * Minor changes
This commit is contained in:
Petr Chornyj
2009-03-30 08:23:58 +00:00
parent ef66cea2e6
commit a07aa6bb23
7 changed files with 2319 additions and 399 deletions

View File

@@ -8,6 +8,36 @@
2009-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org)
*/
2009-03-30 11:30 UTC+0200 Petr Chornyj (myorg63 at mail.ru)
* contrib/hbsqlit3/hbsqlit3.ch
* contrib/hbsqlit3/hbsqlit3.c
* Added support for sqlite_exec() callback.
Now the 3rd parameter is an optional callback that is invoked
once for each row of any query results.
* Now we can pass name of logfile as third parameter of
sqlite3_trace(), sqlite3_profile().
+ Added sqlite3_set_authorizer() -
Compile-Time Authorization Callbacks.
+ Added sqlite3_busy_handler() -
A Callback To Handle SQLITE_BUSY Errors.
+ Added sqlite3_progress_handler() - Query Progress Callbacks.
+ Added sqlite3_commit_hook(), sqlite3_rollback_hook() -
Commit And Rollback Notification Callbacks
+ Added sqlite3_backup_*() API for backups purposes.
+ Added sqlite3_initialize(), sqlite3_shutdown(), sqlite3_interrupt(),
sqlite3_status(), sqlite3_db_status(), sqlite3_stmt_status(),
sqlite3_sql(), sqlite3_extended_errcode(), sqlite3_threadsafe(),
sqlite3_memory_used(), sqlite3_memory_highwater().
! Fixed sqlite3_table_column_metadata().
- Temporary disabled sqlite3_db_handle().
* Minor changes, cleanup and formating.
+ contrib/hbsqlit3/tests/authorizer.prg
+ contrib/hbsqlit3/tests/backup.prg
+ contrib/hbsqlit3/tests/hooks.prg
+ Added for demonstration of new possibilities.
+ contrib/hbsqlit3/tests/metadata.prg
* Minor changes
2009-03-30 10:01 UTC+0200 Viktor Szakats (harbour.01 syenar hu)
* config/win/owatcom.cf
* config/linux/owatcom.cf

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,7 @@
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
* See COPYING for licensing terms.
* See doc/license.txt for licensing terms.
*
*/
@@ -61,45 +61,44 @@
#define SQLITE_INTEGER 1
#define SQLITE_FLOAT 2
#ifdef SQLITE_TEXT
#undef SQLITE_TEXT
#undef SQLITE_TEXT
#else
#define SQLITE_TEXT 3
#define SQLITE_TEXT 3
#endif
#define SQLITE3_TEXT 3
#define SQLITE_BLOB 4
#define SQLITE_NULL 5
#define SQLITE_OK 0 /* Successful result */
#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 */
#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
@@ -117,4 +116,59 @@
#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
#endif

View File

@@ -0,0 +1,255 @@
/*
* $Id$
*/
/*
* SQLite3 Demo. Using sqlite3_set_authorizer()
*
* Copyright 2009 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 software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* 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.
*
* See COPYING for licensing terms.
*
*/
/*
* Using sqlite3_set_authorizer()
*
* This routine registers a authorizer callback with a particular
* database connection, supplied in the first argument.
* The authorizer callback is invoked as SQL statements are being compiled
* by sqlite3_prepare().
*
* When the callback returns SQLITE_OK, that means the operation requested
* is ok.
* When the callback returns SQLITE_DENY, the sqlite3_prepare() or
* equivalent call that triggered the authorizer will fail with an error
* message explaining that access is denied.
* If the authorizer code is SQLITE_READ and the callback returns
* SQLITE_IGNORE then the prepared statement statement is constructed to
* substitute a NULL value in place of the table column that would have
* been read if SQLITE_OK had been returned.
* The SQLITE_IGNORE return can be used to deny an untrusted user access
* to individual columns of a table.
*
* The first parameter to the authorizer callback is an integer
* action code that specifies the particular action to be authorized.
* The second through fourth parameters to the callback are strings
* that contain additional details about the action to be authorized.
*/
#include "common.ch"
#include "hbsqlit3.ch"
FUNCTION main()
LOCAL cFile := ":memory:", cSQLTEXT
LOCAL pDb, cb
//
IF Empty( pDb := PrepareDB(cFile) )
RETURN 1
ENDIF
// Authorizer1
sqlite3_set_authorizer( pDb, @Authorizer() /*"Authorizer"*/ )
QOut( cSQLTEXT := "SELECT * FROM main.person WHERE age BETWEEN 20 AND 40" )
cb := @CallBack() // "CallBack"
Qout( cErrorMsg(sqlite3_exec(pDb, cSQLTEXT, cb)) )
sqlite3_sleep( 3000 )
// Authorizer2
Qout( cErrorMsg(sqlite3_set_authorizer(pDb, @Authorizer2() /*"Authorizer2"*/)) )
QOut( cSQLTEXT := "SELECT * FROM main.person WHERE age BETWEEN 20 AND 40" )
Qout( cErrorMsg(sqlite3_exec(pDb, cSQLTEXT, cb)) )
sqlite3_sleep( 3000 )
// Authorizer3
Qout( cErrorMsg(sqlite3_set_authorizer(pDb, @Authorizer3() /*"Authorizer3"*/)) )
QOut( cSQLTEXT := "SELECT * FROM main.person WHERE age BETWEEN 20 AND 40" )
Qout( cErrorMsg(sqlite3_exec(pDb, cSQLTEXT, cb), FALSE) )
sqlite3_sleep( 3000 )
//
pDb := Nil // close database
//
RETURN 0
/**
*/
FUNCTION Authorizer( nAction, cName1, cName2, cDatabaseName, cTriggerOrViewName )
LOCAL oldColor := SetColor( "R/N" )
//
Qout( "=>", StrZero(nAction, 2), cName1, cName2, cDatabaseName, cTriggerOrViewName )
SetColor( oldColor )
//
RETURN SQLITE_OK
/**
*/
FUNCTION Authorizer2( nAction, cName1, cName2, cDatabaseName, cTriggerOrViewName )
LOCAL oldColor := SetColor( "R/N" )
//
Qout( "=>", StrZero(nAction, 2), cName1, cName2, cDatabaseName, cTriggerOrViewName )
SetColor( oldColor )
//
RETURN iif( cName2 == "pasw", SQLITE_IGNORE, SQLITE_OK )
/**
*/
FUNCTION Authorizer3( nAction, cName1, cName2, cDatabaseName, cTriggerOrViewName )
//
RETURN iif( nAction == SQLITE_SELECT, SQLITE_DENY, SQLITE_OK )
/**
*/
FUNCTION CallBack( nColCount, aValue, aColName )
LOCAL nI
LOCAL oldColor := SetColor( "G/N" )
//
FOR nI := 1 TO nColCount
Qout( Padr(aColName[nI], 5) , " == ", aValue[nI] )
NEXT
SetColor( oldColor )
//
RETURN 0
/**
*/
STATIC FUNCTION cErrorMsg( nError, lShortMsg )
LOCAL aErrorCodes := { ;
{ SQLITE_ERROR , "SQLITE_ERROR" , "SQL error or missing database" }, ;
{ SQLITE_INTERNAL , "SQLITE_INTERNAL" , "NOT USED. Internal logic error in SQLite" }, ;
{ SQLITE_PERM , "SQLITE_PERM" , "Access permission denied" }, ;
{ SQLITE_ABORT , "SQLITE_ABORT" , "Callback routine requested an abort" }, ;
{ SQLITE_BUSY , "SQLITE_BUSY" , "The database file is locked" }, ;
{ SQLITE_LOCKED , "SQLITE_LOCKED" , "A table in the database is locked" }, ;
{ SQLITE_NOMEM , "SQLITE_NOMEM" , "A malloc() failed" }, ;
{ SQLITE_READONLY , "SQLITE_READONLY" , "Attempt to write a readonly database" }, ;
{ SQLITE_INTERRUPT , "SQLITE_INTERRUPT" , "Operation terminated by sqlite3_interrupt()" }, ;
{ SQLITE_IOERR , "SQLITE_IOERR" , "Some kind of disk I/O error occurred" }, ;
{ SQLITE_CORRUPT , "SQLITE_CORRUPT" , "The database disk image is malformed" }, ;
{ SQLITE_NOTFOUND , "SQLITE_NOTFOUND" , "NOT USED. Table or record not found" }, ;
{ SQLITE_FULL , "SQLITE_FULL" , "Insertion failed because database is full" }, ;
{ SQLITE_CANTOPEN , "SQLITE_CANTOPEN" , "Unable to open the database file" }, ;
{ SQLITE_PROTOCOL , "SQLITE_PROTOCOL" , "NOT USED. Database lock protocol error" }, ;
{ SQLITE_EMPTY , "SQLITE_EMPTY" , "Database is empty" }, ;
{ SQLITE_SCHEMA , "SQLITE_SCHEMA" , "The database schema changed" }, ;
{ SQLITE_TOOBIG , "SQLITE_TOOBIG" , "String or BLOB exceeds size limit" }, ;
{ SQLITE_CONSTRAINT , "SQLITE_CONSTRAINT" , "Abort due to constraint violation" }, ;
{ SQLITE_MISMATCH , "SQLITE_MISMATCH" , "Data type mismatch" }, ;
{ SQLITE_MISUSE , "SQLITE_MISUSE" , "Library used incorrectly" }, ;
{ SQLITE_NOLFS , "SQLITE_NOLFS" , "Uses OS features not supported on host" }, ;
{ SQLITE_AUTH , "SQLITE_AUTH" , "Authorization denied" }, ;
{ SQLITE_FORMAT , "SQLITE_FORMAT" , "Auxiliary database format error" }, ;
{ SQLITE_RANGE , "SQLITE_RANGE" , "2nd parameter to sqlite3_bind out of range" }, ;
{ SQLITE_NOTADB , "SQLITE_NOTADB" , "File opened that is not a database file" }, ;
{ SQLITE_ROW , "SQLITE_ROW" , "sqlite3_step() has another row ready" }, ;
{ SQLITE_DONE , "SQLITE_DONE" , "sqlite3_step() has finished executing" } ;
}, nIndex, cErrorMsg := "UNKNOWN"
//
DEFAULT lShortMsg TO TRUE
IF hb_IsNumeric( nError )
IF nError == 0
cErrorMsg := "SQLITE_OK"
ELSE
nIndex := AScan( aErrorCodes, {|x| x[1] == nError } )
cErrorMsg := iif( nIndex > 0, aErrorCodes[ nIndex ][ iif(lShortMsg,2,3) ], cErrorMsg )
ENDIF
ENDIF
//
RETURN cErrorMsg
/**
*/
STATIC FUNCTION PrepareDB( cFile )
LOCAL cSQLTEXT, cMsg
LOCAL pDb, pStmt
LOCAL hPerson := { ;
"Bob" => 52, ;
"Fred" => 32, ;
"Sasha" => 17, ;
"Andy" => 20, ;
"Ivet" => 28 ;
}, enum
//
pDb := sqlite3_open( cFile, TRUE )
IF Empty( pDb )
QOut( "Can't open/create database : ", cFile )
RETURN NIL
ENDIF
cSQLTEXT := "CREATE TABLE person( name TEXT, age INTEGER, pasw TEXT(32) )"
cMsg := cErrorMsg( sqlite3_exec(pDb, cSQLTEXT) )
IF cMsg <> "SQLITE_OK"
QOut( "Can't create table : person" )
pDb := NIL // close database
RETURN NIL
ENDIF
//
cSQLTEXT := "INSERT INTO person( name, age, pasw ) VALUES( :name, :age, :pasw )"
pStmt := sqlite3_prepare( pDb, cSQLTEXT )
IF Empty( pStmt )
QOut( "Can't prepare statement : ", cSQLTEXT )
pDb := NIL
RETURN NIL
ENDIF
FOR EACH enum IN hPerson
sqlite3_reset( pStmt )
sqlite3_bind_text( pStmt, 1, enum:__enumKey )
sqlite3_bind_int( pStmt, 2, enum:__enumValue )
sqlite3_bind_text( pStmt, 3, hb_md5(enum:__enumKey) )
sqlite3_step( pStmt )
NEXT
sqlite3_clear_bindings( pStmt )
sqlite3_finalize( pStmt )
//
RETURN pDb

View File

@@ -0,0 +1,236 @@
/*
* $Id$
*/
/*
* SQLite3 Demo. Using sqlite3_backup_*()
*
* Copyright 2009 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 software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* 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.
*
* See COPYING for licensing terms.
*
*/
/*
* Using sqlite3_backup_*()
*
* This API is used to overwrite the contents of one database with that
* of another. It is useful either for creating backups of databases or
* for copying in-memory databases to or from persistent files.
*
* sqlite3_backup_init() is called once to initialize the backup,
* sqlite3_backup_step() is called one or more times to transfer the data
* between the two databases, and finally
* sqlite3_backup_finish() is called to release all resources associated
* with the backup operation.
*/
#include "common.ch"
#include "hbsqlit3.ch"
FUNCTION main()
LOCAL cFileSource := ":memory:", cFileDest := "backup.db", cSQLTEXT
LOCAL pDbSource, pDbDest, pBackup, cb, nDbFlags
//
IF sqlite3_libversion_number() < 3006011
RETURN 1
ENDIF
IF Empty( pDbSource := PrepareDB(cFileSource) )
RETURN 1
ENDIF
nDbFlags := SQLITE_OPEN_CREATE + SQLITE_OPEN_READWRITE + ;
SQLITE_OPEN_EXCLUSIVE
pDbDest := sqlite3_open_v2( cFileDest, nDbFlags )
IF Empty( pDbDest )
QOut( "Can't open database : ", cFileDest )
RETURN 1
ENDIF
sqlite3_trace( pDbDest, TRUE, "backup.log" )
//
pBackup := sqlite3_backup_init( pDbDest, "main", pDbSource, "main" )
IF Empty( pBackup )
QOut( "Can't initialize backup" )
RETURN 1
ELSE
QOut( "Start backup.." )
ENDIF
IF sqlite3_backup_step(pBackup, -1) == SQLITE_DONE
QOut( "Backup successful." )
ENDIF
sqlite3_backup_finish( pBackup ) /* !!! */
pDbSource := Nil /* close :memory: database */
/* Little test for sqlite3_exec with callback */
QOut( "" )
QOut( cSQLTEXT := "SELECT * FROM main.person WHERE age BETWEEN 20 AND 40" )
cb := @CallBack() // "CallBack"
Qout( cErrorMsg(sqlite3_exec(pDbDest, cSQLTEXT, cb)) )
pDbDest := Nil // close database
sqlite3_sleep( 3000 )
//
RETURN 0
/**
*/
FUNCTION CallBack( nColCount, aValue, aColName )
LOCAL nI
LOCAL oldColor := SetColor( "G/N" )
//
FOR nI := 1 TO nColCount
Qout( Padr(aColName[nI], 5) , " == ", aValue[nI] )
NEXT
SetColor( oldColor )
//
RETURN 0
/**
*/
STATIC FUNCTION cErrorMsg( nError, lShortMsg )
LOCAL aErrorCodes := { ;
{ SQLITE_ERROR , "SQLITE_ERROR" , "SQL error or missing database" }, ;
{ SQLITE_INTERNAL , "SQLITE_INTERNAL" , "NOT USED. Internal logic error in SQLite" }, ;
{ SQLITE_PERM , "SQLITE_PERM" , "Access permission denied" }, ;
{ SQLITE_ABORT , "SQLITE_ABORT" , "Callback routine requested an abort" }, ;
{ SQLITE_BUSY , "SQLITE_BUSY" , "The database file is locked" }, ;
{ SQLITE_LOCKED , "SQLITE_LOCKED" , "A table in the database is locked" }, ;
{ SQLITE_NOMEM , "SQLITE_NOMEM" , "A malloc() failed" }, ;
{ SQLITE_READONLY , "SQLITE_READONLY" , "Attempt to write a readonly database" }, ;
{ SQLITE_INTERRUPT , "SQLITE_INTERRUPT" , "Operation terminated by sqlite3_interrupt()" }, ;
{ SQLITE_IOERR , "SQLITE_IOERR" , "Some kind of disk I/O error occurred" }, ;
{ SQLITE_CORRUPT , "SQLITE_CORRUPT" , "The database disk image is malformed" }, ;
{ SQLITE_NOTFOUND , "SQLITE_NOTFOUND" , "NOT USED. Table or record not found" }, ;
{ SQLITE_FULL , "SQLITE_FULL" , "Insertion failed because database is full" }, ;
{ SQLITE_CANTOPEN , "SQLITE_CANTOPEN" , "Unable to open the database file" }, ;
{ SQLITE_PROTOCOL , "SQLITE_PROTOCOL" , "NOT USED. Database lock protocol error" }, ;
{ SQLITE_EMPTY , "SQLITE_EMPTY" , "Database is empty" }, ;
{ SQLITE_SCHEMA , "SQLITE_SCHEMA" , "The database schema changed" }, ;
{ SQLITE_TOOBIG , "SQLITE_TOOBIG" , "String or BLOB exceeds size limit" }, ;
{ SQLITE_CONSTRAINT , "SQLITE_CONSTRAINT" , "Abort due to constraint violation" }, ;
{ SQLITE_MISMATCH , "SQLITE_MISMATCH" , "Data type mismatch" }, ;
{ SQLITE_MISUSE , "SQLITE_MISUSE" , "Library used incorrectly" }, ;
{ SQLITE_NOLFS , "SQLITE_NOLFS" , "Uses OS features not supported on host" }, ;
{ SQLITE_AUTH , "SQLITE_AUTH" , "Authorization denied" }, ;
{ SQLITE_FORMAT , "SQLITE_FORMAT" , "Auxiliary database format error" }, ;
{ SQLITE_RANGE , "SQLITE_RANGE" , "2nd parameter to sqlite3_bind out of range" }, ;
{ SQLITE_NOTADB , "SQLITE_NOTADB" , "File opened that is not a database file" }, ;
{ SQLITE_ROW , "SQLITE_ROW" , "sqlite3_step() has another row ready" }, ;
{ SQLITE_DONE , "SQLITE_DONE" , "sqlite3_step() has finished executing" } ;
}, nIndex, cErrorMsg := "UNKNOWN"
//
DEFAULT lShortMsg TO TRUE
IF hb_IsNumeric( nError )
IF nError == 0
cErrorMsg := "SQLITE_OK"
ELSE
nIndex := AScan( aErrorCodes, {|x| x[1] == nError } )
cErrorMsg := iif( nIndex > 0, aErrorCodes[ nIndex ][ iif(lShortMsg,2,3) ], cErrorMsg )
ENDIF
ENDIF
//
RETURN cErrorMsg
/**
*/
STATIC FUNCTION PrepareDB( cFile )
LOCAL cSQLTEXT, cMsg
LOCAL pDb, pStmt
LOCAL hPerson := { ;
"Bob" => 52, ;
"Fred" => 32, ;
"Sasha" => 17, ;
"Andy" => 20, ;
"Ivet" => 28 ;
}, enum
//
pDb := sqlite3_open( cFile, TRUE )
IF Empty( pDb )
QOut( "Can't open/create database : ", cFile )
RETURN NIL
ENDIF
sqlite3_trace( pDb, TRUE, "backup.log" )
cSQLTEXT := "CREATE TABLE person( name TEXT, age INTEGER )"
cMsg := cErrorMsg( sqlite3_exec(pDb, cSQLTEXT) )
IF cMsg <> "SQLITE_OK"
QOut( "Can't create table : person" )
pDb := NIL // close database
RETURN NIL
ENDIF
//
cSQLTEXT := "INSERT INTO person( name, age ) VALUES( :name, :age )"
pStmt := sqlite3_prepare( pDb, cSQLTEXT )
IF Empty( pStmt )
QOut( "Can't prepare statement : ", cSQLTEXT )
pDb := NIL
RETURN NIL
ENDIF
FOR EACH enum IN hPerson
sqlite3_reset( pStmt )
sqlite3_bind_text( pStmt, 1, enum:__enumKey )
sqlite3_bind_int( pStmt, 2, enum:__enumValue )
sqlite3_step( pStmt )
NEXT
sqlite3_clear_bindings( pStmt )
sqlite3_finalize( pStmt )
//
RETURN pDb

View File

@@ -0,0 +1,251 @@
/*
* $Id$
*/
/*
* SQLite3 Demo. Using sqlite3_commit_hook(), sqlite3_rollback_hook()
*
* Copyright 2009 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 software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* 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.
*
* See COPYING for licensing terms.
*
*/
#include "common.ch"
#include "hbsqlit3.ch"
FUNCTION main()
LOCAL cSQLTEXT, cFile := ":memory:"
LOCAL pDb, cb := @CallBack()
//
IF Empty( pDb := PrepareDB(cFile) )
RETURN 1
ENDIF
//
sqlite3_commit_hook( pDb, "HookCommitY" )
QOut( cSQLTEXT := "SELECT * FROM person WHERE name == 'Andy'" )
Qout( "return value: ", cErrorMsg(sqlite3_exec(pDb, cSQLTEXT, cb)) )
QOut( cSQLTEXT := "BEGIN EXCLUSIVE TRANSACTION" )
Qout( "return value: ",cErrorMsg(sqlite3_exec(pDb, cSQLTEXT)) )
QOut( cSQLTEXT := "DELETE FROM person WHERE name == 'Andy'" )
Qout( "return value: ", cErrorMsg(sqlite3_exec(pDb, cSQLTEXT)) )
QOut( cSQLTEXT := "END TRANSACTION" )
Qout( "return value: ", cErrorMsg(sqlite3_exec(pDb, cSQLTEXT)) )
QOut( cSQLTEXT := "SELECT * FROM person WHERE name == 'Andy'" )
Qout( "return value: ", cErrorMsg(sqlite3_exec(pDb, cSQLTEXT, cb)) )
QOut( Replicate("-", Len(cSQLTEXT)) )
sqlite3_sleep( 10000 )
//
sqlite3_commit_hook( pDb, @HookCommitN() )
sqlite3_rollback_hook( pDb, @HookRollback() )
QOut( cSQLTEXT := "SELECT * FROM person WHERE name == 'Ivet'" )
Qout( "return value: ", cErrorMsg(sqlite3_exec(pDb, cSQLTEXT, cb)) )
QOut( cSQLTEXT := "BEGIN EXCLUSIVE TRANSACTION" )
Qout( "return value: ", cErrorMsg(sqlite3_exec(pDb, cSQLTEXT)) )
QOut( cSQLTEXT := "DELETE FROM person WHERE name == 'Ivet'" )
Qout( "return value: ", cErrorMsg(sqlite3_exec(pDb, cSQLTEXT)) )
QOut( cSQLTEXT := "END TRANSACTION" )
Qout( "return value: ", cErrorMsg(sqlite3_exec(pDb, cSQLTEXT)) )
QOut( cSQLTEXT := "SELECT * FROM person WHERE name == 'Ivet'" )
Qout( "return value: ", cErrorMsg(sqlite3_exec(pDb, cSQLTEXT, cb)) )
//
pDb := NIL
sqlite3_sleep( 10000 )
//
RETURN 0
/**
*/
FUNCTION CallBack( nColCount, aValue, aColName )
LOCAL nI
LOCAL oldColor := SetColor( "G/N" )
//
FOR nI := 1 TO nColCount
Qout( Padr(aColName[nI], 5) , " == ", aValue[nI] )
NEXT
SetColor( oldColor )
//
RETURN 0
/**
*/
FUNCTION HookCommitY()
LOCAL oldColor := SetColor( "R+/N" )
//
Qout( "!! COMMIT" )
SetColor( oldColor )
//
RETURN 0
FUNCTION HookCommitN()
LOCAL oldColor := SetColor( "B+/N" )
//
Qout( "?? COMMIT or ROLLBACK" )
SetColor( oldColor )
//
RETURN 1 // not 0
FUNCTION HookRollback()
LOCAL oldColor := SetColor( "R+/N" )
//
Qout( "!! ROLLBACK" )
SetColor( oldColor )
//
RETURN 1
/**
*/
STATIC FUNCTION cErrorMsg( nError, lShortMsg )
LOCAL aErrorCodes := { ;
{ SQLITE_ERROR , "SQLITE_ERROR" , "SQL error or missing database" }, ;
{ SQLITE_INTERNAL , "SQLITE_INTERNAL" , "NOT USED. Internal logic error in SQLite" }, ;
{ SQLITE_PERM , "SQLITE_PERM" , "Access permission denied" }, ;
{ SQLITE_ABORT , "SQLITE_ABORT" , "Callback routine requested an abort" }, ;
{ SQLITE_BUSY , "SQLITE_BUSY" , "The database file is locked" }, ;
{ SQLITE_LOCKED , "SQLITE_LOCKED" , "A table in the database is locked" }, ;
{ SQLITE_NOMEM , "SQLITE_NOMEM" , "A malloc() failed" }, ;
{ SQLITE_READONLY , "SQLITE_READONLY" , "Attempt to write a readonly database" }, ;
{ SQLITE_INTERRUPT , "SQLITE_INTERRUPT" , "Operation terminated by sqlite3_interrupt()" }, ;
{ SQLITE_IOERR , "SQLITE_IOERR" , "Some kind of disk I/O error occurred" }, ;
{ SQLITE_CORRUPT , "SQLITE_CORRUPT" , "The database disk image is malformed" }, ;
{ SQLITE_NOTFOUND , "SQLITE_NOTFOUND" , "NOT USED. Table or record not found" }, ;
{ SQLITE_FULL , "SQLITE_FULL" , "Insertion failed because database is full" }, ;
{ SQLITE_CANTOPEN , "SQLITE_CANTOPEN" , "Unable to open the database file" }, ;
{ SQLITE_PROTOCOL , "SQLITE_PROTOCOL" , "NOT USED. Database lock protocol error" }, ;
{ SQLITE_EMPTY , "SQLITE_EMPTY" , "Database is empty" }, ;
{ SQLITE_SCHEMA , "SQLITE_SCHEMA" , "The database schema changed" }, ;
{ SQLITE_TOOBIG , "SQLITE_TOOBIG" , "String or BLOB exceeds size limit" }, ;
{ SQLITE_CONSTRAINT , "SQLITE_CONSTRAINT" , "Abort due to constraint violation" }, ;
{ SQLITE_MISMATCH , "SQLITE_MISMATCH" , "Data type mismatch" }, ;
{ SQLITE_MISUSE , "SQLITE_MISUSE" , "Library used incorrectly" }, ;
{ SQLITE_NOLFS , "SQLITE_NOLFS" , "Uses OS features not supported on host" }, ;
{ SQLITE_AUTH , "SQLITE_AUTH" , "Authorization denied" }, ;
{ SQLITE_FORMAT , "SQLITE_FORMAT" , "Auxiliary database format error" }, ;
{ SQLITE_RANGE , "SQLITE_RANGE" , "2nd parameter to sqlite3_bind out of range" }, ;
{ SQLITE_NOTADB , "SQLITE_NOTADB" , "File opened that is not a database file" }, ;
{ SQLITE_ROW , "SQLITE_ROW" , "sqlite3_step() has another row ready" }, ;
{ SQLITE_DONE , "SQLITE_DONE" , "sqlite3_step() has finished executing" } ;
}, nIndex, cErrorMsg := "UNKNOWN"
//
DEFAULT lShortMsg TO TRUE
IF hb_IsNumeric( nError )
IF nError == 0
cErrorMsg := "SQLITE_OK"
ELSE
nIndex := AScan( aErrorCodes, {|x| x[1] == nError } )
cErrorMsg := iif( nIndex > 0, aErrorCodes[ nIndex ][ iif(lShortMsg,2,3) ], cErrorMsg )
ENDIF
ENDIF
//
RETURN cErrorMsg
/**
*/
STATIC FUNCTION PrepareDB( cFile )
LOCAL cSQLTEXT, cMsg
LOCAL pDb, pStmt
LOCAL hPerson := { ;
"Bob" => 52, ;
"Fred" => 32, ;
"Sasha" => 17, ;
"Andy" => 20, ;
"Ivet" => 28 ;
}, enum
//
pDb := sqlite3_open( cFile, TRUE )
IF Empty( pDb )
QOut( "Can't open/create database : ", cFile )
RETURN NIL
ENDIF
Qout( cSQLTEXT := "CREATE TABLE person( name TEXT, age INTEGER )" )
cMsg := cErrorMsg( sqlite3_exec(pDb, cSQLTEXT) )
IF cMsg <> "SQLITE_OK"
QOut( "Can't create table : person" )
pDb := NIL // close database
RETURN NIL
ENDIF
//
cSQLTEXT := "INSERT INTO person( name, age ) VALUES( :name, :age )"
pStmt := sqlite3_prepare( pDb, cSQLTEXT )
IF Empty( pStmt )
QOut( "Can't prepare statement : ", cSQLTEXT )
pDb := NIL
RETURN NIL
ENDIF
QOut( sqlite3_sql(pStmt) )
QOut( Replicate("-", Len(cSQLTEXT)) )
FOR EACH enum IN hPerson
sqlite3_reset( pStmt )
sqlite3_bind_text( pStmt, 1, enum:__enumKey )
sqlite3_bind_int( pStmt, 2, enum:__enumValue )
sqlite3_step( pStmt )
NEXT
sqlite3_clear_bindings( pStmt )
sqlite3_finalize( pStmt )
//
RETURN pDb

View File

@@ -52,9 +52,7 @@
#include "hbsqlit3.ch"
#ifdef NODLL
#define SQLITE_ENABLE_COLUMN_METADATA
#endif
//#define SQLITE_ENABLE_COLUMN_METADATA
PROCEDURE main()
LOCAL lCreateIfNotExist := .f.