From f7b2b9a553adfe42c46b22082ce99d9776cb67fd Mon Sep 17 00:00:00 2001 From: Przemyslaw Czerpak Date: Thu, 13 Sep 2007 14:40:24 +0000 Subject: [PATCH] 2007-09-13 16:40 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/include/Makefile + harbour/include/hbsxdef.ch * harbour/include/dbinfo.ch * harbour/include/hbrdddbf.h * harbour/include/hbrddcdx.h * harbour/include/hbrddntx.h * harbour/contrib/bmdbfcdx/hbrddbmcdx.h * harbour/source/rdd/dbf1.c * harbour/source/rdd/workarea.c + added SIx3 compatible triggers support They should work like in SIx3 with some intentional excpetions: 1) if 4-th parameter exists (PREUSE/GET/PUT) then it's passed by reference otherwise is not passed at all and PCOUNT() in trigger functions returns 3 SIx3 do not pass 4-th parameter by reference and if it not exist then passes 0 2) EVENT_POSTCLOSE is executed after SUPER_CLOSE() SIx3 executes EVENT_POSTCLOSE just before SUPER_CLOSE() 3) EVENT_UPDATE is executed _ALWAYS_ when DBF is updated also when WA does not have open indexes SIx3 executes EVENT_UPDATE only when at least one index is open without checking if it's updated or not 4) EVENT_POSTUSE is executed from OPEN() method in "DBF" RDD not from index RDDs so before the indexes are open SIx3 executes EVENT_POSTUSE after opening indexes It's possible that I'll change this condition in the future --- harbour/ChangeLog | 28 ++ harbour/contrib/bmdbfcdx/hbrddbmcdx.h | 1 + harbour/include/Makefile | 3 +- harbour/include/dbinfo.ch | 1 + harbour/include/hbrddcdx.h | 1 + harbour/include/hbrdddbf.h | 6 + harbour/include/hbrddntx.h | 1 + harbour/include/hbsxdef.ch | 91 +++++ harbour/source/rdd/dbf1.c | 519 ++++++++++++++++++++++---- harbour/source/rdd/workarea.c | 1 + 10 files changed, 570 insertions(+), 82 deletions(-) create mode 100644 harbour/include/hbsxdef.ch diff --git a/harbour/ChangeLog b/harbour/ChangeLog index f6d9ca778b..98af031b0b 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,34 @@ 2002-12-01 13:30 UTC+0100 Foo Bar */ +2007-09-13 16:40 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/include/Makefile + + harbour/include/hbsxdef.ch + * harbour/include/dbinfo.ch + * harbour/include/hbrdddbf.h + * harbour/include/hbrddcdx.h + * harbour/include/hbrddntx.h + * harbour/contrib/bmdbfcdx/hbrddbmcdx.h + * harbour/source/rdd/dbf1.c + * harbour/source/rdd/workarea.c + + added SIx3 compatible triggers support + They should work like in SIx3 with some intentional excpetions: + 1) if 4-th parameter exists (PREUSE/GET/PUT) then it's passed by + reference otherwise is not passed at all and PCOUNT() in trigger + functions returns 3 + SIx3 do not pass 4-th parameter by reference and if it not + exist then passes 0 + 2) EVENT_POSTCLOSE is executed after SUPER_CLOSE() + SIx3 executes EVENT_POSTCLOSE just before SUPER_CLOSE() + 3) EVENT_UPDATE is executed _ALWAYS_ when DBF is updated also + when WA does not have open indexes + SIx3 executes EVENT_UPDATE only when at least one index is + open without checking if it's updated or not + 4) EVENT_POSTUSE is executed from OPEN() method in "DBF" RDD not + from index RDDs so before the indexes are open + SIx3 executes EVENT_POSTUSE after opening indexes + It's possible that I'll change this condition in the future + 2007-09-13 13:30 UTC+0100 Viktor Szakats (harbour.01 syenar.hu) * makefile.vc * makefile.gc diff --git a/harbour/contrib/bmdbfcdx/hbrddbmcdx.h b/harbour/contrib/bmdbfcdx/hbrddbmcdx.h index ff13963f86..6d002637fa 100644 --- a/harbour/contrib/bmdbfcdx/hbrddbmcdx.h +++ b/harbour/contrib/bmdbfcdx/hbrddbmcdx.h @@ -515,6 +515,7 @@ typedef struct _CDXAREA BOOL fFLocked; /* TRUE if file is locked */ BOOL fHeaderLocked; /* TRUE if DBF header is locked */ BOOL fTrigger; /* Execute trigger function */ + LPDBOPENINFO lpdbOpenInfo; /* Pointer to current dbOpenInfo structure in OPEN/CREATE methods */ LPDBRELINFO lpdbPendingRel; /* Pointer to parent rel struct */ ULONG * pLocksPos; /* List of records locked */ ULONG ulNumLocksPos; /* Number of records locked */ diff --git a/harbour/include/Makefile b/harbour/include/Makefile index 4509d703e6..f7c6c7300f 100644 --- a/harbour/include/Makefile +++ b/harbour/include/Makefile @@ -100,7 +100,8 @@ PRG_HEADERS=\ setcurs.ch \ simpleio.ch \ std.ch \ - tbrowse.ch + hbsxdef.ch \ + tbrowse.ch \ API_HEADERS=\ error.api \ diff --git a/harbour/include/dbinfo.ch b/harbour/include/dbinfo.ch index dda93a20a7..d892df862d 100644 --- a/harbour/include/dbinfo.ch +++ b/harbour/include/dbinfo.ch @@ -104,6 +104,7 @@ /* misc */ #define RDDI_PENDINGTRIGGER 40 /* set pending trigger for next open operation */ #define RDDI_PENDINGPASSWORD 41 /* set pending password for next open operation */ +#define RDDI_PASSWORD 42 /* Get/Set default password */ /* Constants for SELF_ORDINFO () diff --git a/harbour/include/hbrddcdx.h b/harbour/include/hbrddcdx.h index fcb64d283e..4c90455515 100644 --- a/harbour/include/hbrddcdx.h +++ b/harbour/include/hbrddcdx.h @@ -515,6 +515,7 @@ typedef struct _CDXAREA BOOL fFLocked; /* TRUE if file is locked */ BOOL fHeaderLocked; /* TRUE if DBF header is locked */ BOOL fTrigger; /* Execute trigger function */ + LPDBOPENINFO lpdbOpenInfo; /* Pointer to current dbOpenInfo structure in OPEN/CREATE methods */ LPDBRELINFO lpdbPendingRel; /* Pointer to parent rel struct */ ULONG * pLocksPos; /* List of records locked */ ULONG ulNumLocksPos; /* Number of records locked */ diff --git a/harbour/include/hbrdddbf.h b/harbour/include/hbrdddbf.h index 4467b09137..bd08a055fe 100644 --- a/harbour/include/hbrdddbf.h +++ b/harbour/include/hbrdddbf.h @@ -113,6 +113,11 @@ typedef struct _DBFDATA char szIndexExt[ HB_MAX_FILE_EXT + 1 ]; char szMemoExt[ HB_MAX_FILE_EXT + 1 ]; + char * szPasswd; + char * szPendingPasswd; + char * szTrigger; + char * szPendingTrigger; + BYTE bLockType; /* 0 */ BYTE bTableType; /* DB_DBF_STD */ BYTE bCryptType; /* DB_CRYPT_NONE */ @@ -208,6 +213,7 @@ typedef struct _DBFAREA BOOL fFLocked; /* TRUE if file is locked */ BOOL fHeaderLocked; /* TRUE if DBF header is locked */ BOOL fTrigger; /* Execute trigger function */ + LPDBOPENINFO lpdbOpenInfo; /* Pointer to current dbOpenInfo structure in OPEN/CREATE methods */ LPDBRELINFO lpdbPendingRel; /* Pointer to parent rel struct */ ULONG * pLocksPos; /* List of records locked */ ULONG ulNumLocksPos; /* Number of records locked */ diff --git a/harbour/include/hbrddntx.h b/harbour/include/hbrddntx.h index b5ef2f3557..a36ffaf788 100644 --- a/harbour/include/hbrddntx.h +++ b/harbour/include/hbrddntx.h @@ -408,6 +408,7 @@ typedef struct _NTXAREA BOOL fFLocked; /* TRUE if file is locked */ BOOL fHeaderLocked; /* TRUE if DBF header is locked */ BOOL fTrigger; /* Execute trigger function */ + LPDBOPENINFO lpdbOpenInfo; /* Pointer to current dbOpenInfo structure in OPEN/CREATE methods */ LPDBRELINFO lpdbPendingRel; /* Pointer to parent rel struct */ ULONG * pLocksPos; /* List of records locked */ ULONG ulNumLocksPos; /* Number of records locked */ diff --git a/harbour/include/hbsxdef.ch b/harbour/include/hbsxdef.ch new file mode 100644 index 0000000000..405291959a --- /dev/null +++ b/harbour/include/hbsxdef.ch @@ -0,0 +1,91 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * SIx3 compatible constants + * + * Copyright 2007 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * 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. + * + */ + +#ifndef HB_SIX_DEF_CH_ +#define HB_SIX_DEF_CH_ + +/* + * Event Constants for Trigger System + */ +#define EVENT_PREUSE 1 +#define EVENT_POSTUSE 2 +#define EVENT_UPDATE 3 +#define EVENT_APPEND 4 +#define EVENT_DELETE 5 +#define EVENT_RECALL 6 +#define EVENT_PACK 7 +#define EVENT_ZAP 8 +#define EVENT_PUT 9 +#define EVENT_GET 10 +#define EVENT_PRECLOSE 11 +#define EVENT_POSTCLOSE 12 +#define EVENT_PREMEMOPACK 13 +#define EVENT_POSTMEMOPACK 14 + +/* + * Trigger Toggle Values + */ +#define TRIGGER_ENABLE 1 +#define TRIGGER_DISABLE 2 +#define TRIGGER_REMOVE 3 +#define TRIGGER_INSTALL 4 +#define TRIGGER_PENDING 5 /* Internal Use Only */ + + +/* + * Sx_File2BLOB() actions + */ +#define BLOB_FILECOMPRESS 1 +#define BLOB_FILEENCRYPT 2 + + +#endif /* HB_SIX_DEF_CH_ */ diff --git a/harbour/source/rdd/dbf1.c b/harbour/source/rdd/dbf1.c index 10ad68d947..cd337c36da 100644 --- a/harbour/source/rdd/dbf1.c +++ b/harbour/source/rdd/dbf1.c @@ -50,6 +50,8 @@ * */ +#define HB_TRIGVAR_BYREF + #include "hbapi.h" #include "hbinit.h" #include "hbvm.h" @@ -65,11 +67,17 @@ #include "hbsxfunc.h" #include "error.ch" #include "rddsys.ch" +#include "hbsxdef.ch" #ifndef HB_CDP_SUPPORT_OFF # include "hbapicdp.h" #endif +#ifdef HB_TRIGVAR_BYREF +#include "hbxvm.h" +#include "hbstack.h" +#endif + static USHORT s_uiRddId = ( USHORT ) -1; static RDDFUNCS dbfSuper; static const RDDFUNCS dbfTable = { ( DBENTRYP_BP ) hb_dbfBof, @@ -220,6 +228,137 @@ static void hb_dbfSetBlankRecord( DBFAREAP pArea ) memset( pPtr, '\0', ( ULONG ) pArea->uiRecordLen - ulSize ); } +/* + * Executes user trigger function + */ +static BOOL hb_dbfTriggerDo( DBFAREAP pArea, int iEvent, + int iField, PHB_ITEM pItem ) +{ + BOOL fResult = TRUE; + + if( hb_vmRequestQuery() == 0 ) + { + if( hb_vmRequestReenter() ) + { +#ifdef HB_TRIGVAR_BYREF + LONG lOffset = 0; + + if( pItem ) + { + lOffset = hb_stackTopOffset() - hb_stackBaseOffset(); + hb_vmPush( pItem ); + } +#endif + + hb_vmPushDynSym( pArea->pTriggerSym ); + hb_vmPushNil(); + /* nEvent */ + hb_vmPushInteger( iEvent ); + /* nArea */ + hb_vmPushInteger( pArea->uiArea ); + /* nFieldPos (GET/PUT) */ + hb_vmPushInteger( iField ); + /* xTrigVal (PREUSE/GET/PUT) */ + if( pItem ) + { + hb_xvmPushLocalByRef( ( SHORT ) lOffset ); + hb_vmDo( 4 ); + } + else + { + /* SIx3 makes: hb_vmPushInteger( 0 ); */ + hb_vmDo( 3 ); + } + +#ifdef HB_TRIGVAR_BYREF + if( pItem ) + { + hb_itemMove( pItem, hb_stackItemFromBase( lOffset ) ); + hb_stackPop(); + } +#endif + fResult = hb_parl( -1 ); + hb_vmRequestRestore(); + } + } + + return fResult; +} + +/* + * Set user trigger function + */ +static void hb_dbfTriggerSet( DBFAREAP pArea, PHB_ITEM pTrigger ) +{ + char * szName = hb_itemGetCPtr( pTrigger ); + + pArea->pTriggerSym = *szName ? hb_dynsymFindName( szName ) : NULL; + if( pArea->pTriggerSym && !hb_dynsymIsFunction( pArea->pTriggerSym ) ) + pArea->pTriggerSym = NULL; + pArea->fTrigger = pArea->pTriggerSym != NULL; +} + +/* + * Set encryption password + */ +static BOOL hb_dbfPasswordSet( DBFAREAP pArea, PHB_ITEM pPasswd ) +{ + BYTE byBuffer[ 8 ]; + ULONG ulLen = 0; + BOOL fSet = !pArea->fHasMemo && HB_IS_STRING( pPasswd ); + BOOL fKeySet = FALSE; + + if( fSet ) + { + ulLen = hb_itemGetCLen( pPasswd ); + if( ulLen > 0 ) + { + if( ulLen < 8 ) + { + memcpy( byBuffer, hb_itemGetCPtr( pPasswd ), ulLen ); + memset( byBuffer + ulLen, '\0', 8 - ulLen ); + } + else + memcpy( byBuffer, hb_itemGetCPtr( pPasswd ), 8 ); + } + } + + if( pArea->pCryptKey ) + hb_itemPutCL( pPasswd, ( char * ) pArea->pCryptKey, 8 ); + else + hb_itemClear( pPasswd ); + + if( fSet ) + { + if( pArea->pRecord && pArea->fPositioned ) + { + SELF_GOCOLD( ( AREAP ) pArea ); + pArea->fValidBuffer = FALSE; + } + if( pArea->pCryptKey ) + { + /* clean the memory with password key - though it's not + * a serious actions in such case ;-) + */ + memset( pArea->pCryptKey, '\0', 8 ); + hb_xfree( pArea->pCryptKey ); + pArea->pCryptKey = NULL; + } + if( ulLen > 0 ) + { + /* at this moment only one encryption method is used, + I'll add other later, [druzus] */ + pArea->bCryptType = DB_CRYPT_SIX; + pArea->pCryptKey = ( BYTE * ) hb_xgrab( 8 ); + /* SIX encode the key with its own value before use */ + hb_sxEnCrypt( byBuffer, pArea->pCryptKey, byBuffer, 8 ); + fKeySet = TRUE; + } + } + + return fKeySet; +} + /* * Return the total number of records. */ @@ -1213,7 +1352,11 @@ static ERRCODE hb_dbfAppend( DBFAREAP pArea, BOOL bUnLockAll ) if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; - /* TODO: EVENT_APPEND call (stopped) */ + if( pArea->fTrigger ) + { + if( !hb_dbfTriggerDo( pArea, EVENT_APPEND, 0, NULL ) ) + return FAILURE; + } if( pArea->fReadonly ) { @@ -1295,7 +1438,11 @@ static ERRCODE hb_dbfDeleteRec( DBFAREAP pArea ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfDeleteRec(%p)", pArea)); - /* TODO: EVENT_DELETE call (stopped) */ + if( pArea->fTrigger ) + { + if( !hb_dbfTriggerDo( pArea, EVENT_DELETE, 0, NULL ) ) + return FAILURE; + } if( pArea->lpdbPendingRel ) { @@ -1615,6 +1762,13 @@ static ERRCODE hb_dbfGetValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) hb_itemRelease( pError ); return FAILURE; } + + if( pArea->fTrigger ) + { + if( !hb_dbfTriggerDo( pArea, EVENT_GET, uiIndex + 1, pItem ) ) + return FAILURE; + } + return SUCCESS; } @@ -1639,6 +1793,19 @@ static ERRCODE hb_dbfGoCold( DBFAREAP pArea ) if( pArea->fRecordChanged ) { + if( pArea->fTrigger ) + { + /* The pending relation may move the record pointer so we should + disable them for trigger evaluation */ + LPDBRELINFO lpdbPendingRel = pArea->lpdbPendingRel; + pArea->lpdbPendingRel = NULL; + + hb_dbfTriggerDo( pArea, EVENT_UPDATE, 0, NULL ); + + /* Restore disabled pending relation */ + pArea->lpdbPendingRel = lpdbPendingRel; + } + /* Write current record */ if( ! hb_dbfWriteRecord( pArea ) ) return FAILURE; @@ -1778,7 +1945,8 @@ static ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) LPFIELD pField; /* this buffer is for date and number conversion, * DBASE documentation defines maximum numeric field size as 20 - * but Clipper allows to create longer fields so I remove this limit, Druzus + * but Clipper allows to create longer fields so I removed this + * limit [druzus] */ char szBuffer[ 256 ]; PHB_ITEM pError; @@ -1786,6 +1954,12 @@ static ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) HB_TRACE(HB_TR_DEBUG, ("hb_dbfPutValue(%p, %hu, %p)", pArea, uiIndex, pItem)); + if( pArea->fTrigger ) + { + if( !hb_dbfTriggerDo( pArea, EVENT_PUT, uiIndex, pItem ) ) + return FAILURE; + } + if( pArea->lpdbPendingRel ) { if( SELF_FORCEREL( ( AREAP ) pArea ) != SUCCESS ) @@ -2020,6 +2194,12 @@ static ERRCODE hb_dbfRecall( DBFAREAP pArea ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfRecall(%p)", pArea)); + if( pArea->fTrigger ) + { + if( !hb_dbfTriggerDo( pArea, EVENT_RECALL, 0, NULL ) ) + return FAILURE; + } + if( pArea->lpdbPendingRel ) { if( SELF_FORCEREL( ( AREAP ) pArea ) != SUCCESS ) @@ -2129,11 +2309,16 @@ static ERRCODE hb_dbfSetFieldExtent( DBFAREAP pArea, USHORT uiFieldExtent ) static ERRCODE hb_dbfClose( DBFAREAP pArea ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfClose(%p)", pArea)); + + if( pArea->fTrigger ) + { + if( !hb_dbfTriggerDo( pArea, EVENT_PRECLOSE, 0, NULL ) ) + return FAILURE; + } + /* Reset parent rel struct */ pArea->lpdbPendingRel = NULL; - SUPER_CLOSE( ( AREAP ) pArea ); - /* Update record and unlock records */ if( pArea->hDataFile != FS_ERROR ) { @@ -2145,16 +2330,18 @@ static ERRCODE hb_dbfClose( DBFAREAP pArea ) /* Update header */ if( pArea->fUpdateHeader ) - { SELF_WRITEDBHEADER( ( AREAP ) pArea ); - } /* It's not Clipper compatible but it reduces the problem with byggy Windows network setting */ if( hb_set.HB_SET_HARDCOMMIT ) - { SELF_FLUSH( ( AREAP ) pArea ); - } + } + + SUPER_CLOSE( ( AREAP ) pArea ); + + if( pArea->hDataFile != FS_ERROR ) + { hb_fsClose( pArea->hDataFile ); pArea->hDataFile = FS_ERROR; } @@ -2200,6 +2387,12 @@ static ERRCODE hb_dbfClose( DBFAREAP pArea ) pArea->szMemoFileName = NULL; } + if( pArea->fTrigger ) + { + hb_dbfTriggerDo( pArea, EVENT_POSTCLOSE, 0, NULL ); + pArea->fTrigger = FALSE; + } + return SUCCESS; } @@ -2218,7 +2411,10 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) HB_TRACE(HB_TR_DEBUG, ("hb_dbfCreate(%p, %p)", pArea, pCreateInfo)); + pArea->lpdbOpenInfo = pCreateInfo; + pFileName = hb_fsFNameSplit( ( char * ) pCreateInfo->abName ); + if( hb_set.HB_SET_DEFEXTENSIONS && ! pFileName->szExtension ) { pItem = hb_itemPutC( pItem, "" ); @@ -2226,6 +2422,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) { hb_itemRelease( pItem ); hb_xfree( pFileName ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } pFileName->szExtension = hb_itemGetCPtr( pItem ); @@ -2238,7 +2435,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) hb_xfree( pFileName ); pItem = hb_itemPutL( pItem, FALSE ); - fRawBlob = SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_BLOB_SUPPORT, 0, pItem ) == SUCCESS && + fRawBlob = SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_BLOB_SUPPORT, pCreateInfo->ulConnection, pItem ) == SUCCESS && hb_itemGetL( pItem ); if( pArea->bTableType == 0 ) @@ -2247,6 +2444,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) if( SELF_INFO( ( AREAP ) pArea, DBI_TABLETYPE, pItem ) != SUCCESS ) { hb_itemRelease( pItem ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } pArea->bTableType = hb_itemGetNI( pItem ); @@ -2258,6 +2456,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) if( SELF_INFO( ( AREAP ) pArea, DBI_LOCKSCHEME, pItem ) != SUCCESS ) { hb_itemRelease( pItem ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } pArea->bLockType = hb_itemGetNI( pItem ); @@ -2278,6 +2477,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) if( SELF_INFO( ( AREAP ) pArea, DBI_MEMOTYPE, pItem ) != SUCCESS ) { hb_itemRelease( pItem ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } pArea->bMemoType = ( BYTE ) hb_itemGetNI( pItem ); @@ -2286,9 +2486,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) pArea->bCryptType = DB_CRYPT_NONE; if( pItem ) - { hb_itemRelease( pItem ); - } if( pArea->uiFieldCount * sizeof( DBFFIELD ) + sizeof( DBFHEADER ) + ( pArea->bTableType == DB_DBF_VFP ? 1 : 2 ) > UINT16_MAX ) @@ -2300,6 +2498,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) hb_errPutFileName( pError, ( char * ) pCreateInfo->abName ); SELF_ERROR( ( AREAP ) pArea, pError ); hb_itemRelease( pError ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } @@ -2338,6 +2537,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) if( pArea->hDataFile == FS_ERROR ) { + pArea->lpdbOpenInfo = NULL; return FAILURE; } } @@ -2474,6 +2674,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) hb_errPutFileName( pError, ( char * ) pCreateInfo->abName ); SELF_ERROR( ( AREAP ) pArea, pError ); hb_itemRelease( pError ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } pThisField++ ; @@ -2504,6 +2705,25 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) pArea->cdPage = hb_cdp_page; #endif + pItem = hb_itemNew( NULL ); + if( SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_PENDINGPASSWORD, + pCreateInfo->ulConnection, pItem ) == SUCCESS ) + { + if( hb_dbfPasswordSet( pArea, pItem ) ) + pArea->fTableEncrypted = TRUE; + } + else + { + hb_itemClear( pItem ); + if( SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_PASSWORD, + pCreateInfo->ulConnection, pItem ) == SUCCESS ) + { + if( hb_dbfPasswordSet( pArea, pItem ) ) + pArea->fTableEncrypted = TRUE; + } + } + hb_itemRelease( pItem ); + if( !fRawBlob ) { /* Force write new header */ @@ -2515,6 +2735,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) if( pBuffer ) hb_xfree( pBuffer ); SELF_CLOSE( ( AREAP ) pArea ); + pArea->lpdbOpenInfo = NULL; return errCode; } @@ -2528,6 +2749,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) if( pBuffer ) hb_xfree( pBuffer ); SELF_CLOSE( ( AREAP ) pArea ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } @@ -2555,6 +2777,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) if( errCode != SUCCESS ) { SELF_CLOSE( ( AREAP ) pArea ); + pArea->lpdbOpenInfo = NULL; return errCode; } @@ -2564,6 +2787,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) /* Update the number of record for corrupted headers */ pArea->ulRecCount = hb_dbfCalcRecCount( pArea ); + pArea->lpdbOpenInfo = NULL; /* Position cursor at the first record */ return SELF_GOTOP( ( AREAP ) pArea ); @@ -2714,62 +2938,25 @@ static ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) break; case DBI_PASSWORD: + hb_dbfPasswordSet( pArea, pItem ); + break; + + case DBI_TRIGGER: + if( HB_IS_LOGICAL( pItem ) ) + pArea->fTrigger = hb_itemGetL( pItem ); + else { - BYTE byBuffer[ 8 ]; - ULONG ulLen = 0; - BOOL fSet = !pArea->fHasMemo && HB_IS_STRING( pItem ); - - if( fSet ) - { - ulLen = hb_itemGetCLen( pItem ); - if( ulLen > 0 ) - { - if( ulLen < 8 ) - { - memcpy( byBuffer, hb_itemGetCPtr( pItem ), ulLen ); - memset( byBuffer + ulLen, '\0', 8 - ulLen ); - } - else - { - memcpy( byBuffer, hb_itemGetCPtr( pItem ), 8 ); - } - } - } - - if( pArea->pCryptKey ) - hb_itemPutCL( pItem, ( char * ) pArea->pCryptKey, 8 ); - else - hb_itemClear( pItem ); - - if( fSet ) - { - if( pArea->fPositioned ) - { - errCode = SELF_GOCOLD( ( AREAP ) pArea ); - pArea->fValidBuffer = FALSE; - } - if( pArea->pCryptKey ) - { - /* clean the memory with password key - though it's not - * a serious actions in such case ;-) - */ - memset( pArea->pCryptKey, '\0', 8 ); - hb_xfree( pArea->pCryptKey ); - pArea->pCryptKey = NULL; - } - if( ulLen > 0 ) - { - /* at this moment only one encryption method is used, - I'll add other later, [druzus] */ - pArea->bCryptType = DB_CRYPT_SIX; - pArea->pCryptKey = ( BYTE * ) hb_xgrab( 8 ); - /* SIX encode the key with its own value before use */ - hb_sxEnCrypt( byBuffer, pArea->pCryptKey, byBuffer, 8 ); - } - } + PHB_DYNS pTriggerSym = pArea->pTriggerSym; + if( HB_IS_STRING( pItem ) ) + hb_dbfTriggerSet( pArea, pItem ); + hb_itemPutC( pItem, pTriggerSym ? hb_dynsymName( pTriggerSym ) : NULL ); } break; + case DBI_OPENINFO: + hb_itemPutPtr( pItem, pArea->lpdbOpenInfo ); + break; + case DBI_DB_VERSION: case DBI_RDD_VERSION: { @@ -2955,7 +3142,7 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) ERRCODE errCode; USHORT uiFlags, uiFields, uiSize, uiCount, uiSkip; BOOL fRetry, fRawBlob; - PHB_ITEM pError, pFileExt, pItem; + PHB_ITEM pError, pItem; PHB_FNAME pFileName; BYTE * pBuffer; LPDBFFIELD pField; @@ -2965,19 +3152,53 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) HB_TRACE(HB_TR_DEBUG, ("hb_dbfOpen(%p, %p)", pArea, pOpenInfo)); + pArea->lpdbOpenInfo = pOpenInfo; + + pItem = hb_itemNew( NULL ); + + if( SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_PENDINGTRIGGER, + pOpenInfo->ulConnection, pItem ) == SUCCESS ) + { + if( HB_IS_STRING( pItem ) ) + hb_dbfTriggerSet( pArea, pItem ); + } + + if( !pArea->fTrigger ) + { + if( SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_TRIGGER, + pOpenInfo->ulConnection, pItem ) == SUCCESS ) + { + if( HB_IS_STRING( pItem ) ) + hb_dbfTriggerSet( pArea, pItem ); + } + } + + if( pArea->fTrigger ) + { + hb_itemPutC( pItem, ( char * ) pOpenInfo->abName ); + if( !hb_dbfTriggerDo( pArea, EVENT_PREUSE, 0, pItem ) ) + { + hb_itemRelease( pItem ); + pArea->lpdbOpenInfo = NULL; + return FAILURE; + } + hb_strncpy( ( char * ) szFileName, hb_itemGetCPtr( pItem ), _POSIX_PATH_MAX ); + } + else + hb_strncpy( ( char * ) szFileName, ( char * ) pOpenInfo->abName, _POSIX_PATH_MAX ); + if( !pArea->bLockType ) { - PHB_ITEM pItem = hb_itemNew( NULL ); - + hb_itemClear( pItem ); if( SELF_INFO( ( AREAP ) pArea, DBI_LOCKSCHEME, pItem ) != SUCCESS ) { hb_itemRelease( pItem ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } pArea->bLockType = hb_itemGetNI( pItem ); if( !pArea->bLockType ) pArea->bLockType = DB_DBFLOCK_CLIP; - hb_itemRelease( pItem ); } #ifndef HB_CDP_SUPPORT_OFF if( pOpenInfo->cdpId ) @@ -3002,24 +3223,20 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) (pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE); pError = NULL; - pFileName = hb_fsFNameSplit( ( char * ) pOpenInfo->abName ); + pFileName = hb_fsFNameSplit( ( char * ) szFileName ); /* Add default file name extension if necessary */ if( hb_set.HB_SET_DEFEXTENSIONS && ! pFileName->szExtension ) { - pFileExt = hb_itemPutC( NULL, "" ); - if( SELF_INFO( ( AREAP ) pArea, DBI_TABLEEXT, pFileExt ) != SUCCESS ) + hb_itemClear( pItem ); + if( SELF_INFO( ( AREAP ) pArea, DBI_TABLEEXT, pItem ) != SUCCESS ) { - hb_itemRelease( pFileExt ); hb_xfree( pFileName ); + hb_itemRelease( pItem ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } - pFileName->szExtension = hb_itemGetCPtr( pFileExt ); + pFileName->szExtension = hb_itemGetCPtr( pItem ); hb_fsFNameMerge( ( char * ) szFileName, pFileName ); - hb_itemRelease( pFileExt ); - } - else - { - hb_strncpy( ( char * ) szFileName, ( char * ) pOpenInfo->abName, _POSIX_PATH_MAX ); } /* Create default alias if necessary */ @@ -3030,9 +3247,10 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) } hb_xfree( pFileName ); - pItem = hb_itemPutL( NULL, FALSE ); - fRawBlob = SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_BLOB_SUPPORT, 0, pItem ) == SUCCESS && + hb_itemClear( pItem ); + fRawBlob = SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_BLOB_SUPPORT, pOpenInfo->ulConnection, pItem ) == SUCCESS && hb_itemGetL( pItem ); + hb_itemRelease( pItem ); if( fRawBlob ) @@ -3077,6 +3295,7 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) if( pArea->hDataFile == FS_ERROR ) { SELF_CLOSE( ( AREAP ) pArea ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } @@ -3088,6 +3307,7 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) if( errCode != SUCCESS ) { SELF_CLOSE( ( AREAP ) pArea ); + pArea->lpdbOpenInfo = NULL; return errCode; } @@ -3133,6 +3353,7 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) if( pBuffer ) hb_xfree( pBuffer ); SELF_CLOSE( ( AREAP ) pArea ); + pArea->lpdbOpenInfo = NULL; return errCode; } @@ -3180,6 +3401,7 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) if( errCode != SUCCESS ) { SELF_CLOSE( ( AREAP ) pArea ); + pArea->lpdbOpenInfo = NULL; return errCode; } } @@ -3311,9 +3533,27 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) hb_itemRelease( pError ); } SELF_CLOSE( ( AREAP ) pArea ); + pArea->lpdbOpenInfo = NULL; return errCode; } + pItem = hb_itemNew( NULL ); + if( SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_PENDINGPASSWORD, + pOpenInfo->ulConnection, pItem ) == SUCCESS ) + { + hb_dbfPasswordSet( pArea, pItem ); + } + else + { + hb_itemClear( pItem ); + if( SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_PASSWORD, + pOpenInfo->ulConnection, pItem ) == SUCCESS ) + { + hb_dbfPasswordSet( pArea, pItem ); + } + } + hb_itemRelease( pItem ); + /* Open memo file if exists */ if( pArea->fHasMemo ) { @@ -3334,6 +3574,7 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) if( errCode != SUCCESS ) { SELF_CLOSE( ( AREAP ) pArea ); + pArea->lpdbOpenInfo = NULL; return FAILURE; } @@ -3345,7 +3586,14 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) pArea->ulRecCount = hb_dbfCalcRecCount( pArea ); /* Position cursor at the first record */ - return SELF_GOTOP( ( AREAP ) pArea ); + errCode = SELF_GOTOP( ( AREAP ) pArea ); + + if( pArea->fTrigger ) + hb_dbfTriggerDo( pArea, EVENT_POSTUSE, 0, NULL ); + + pArea->lpdbOpenInfo = NULL; + + return errCode; } /* @@ -3419,6 +3667,12 @@ static ERRCODE hb_dbfPack( DBFAREAP pArea ) return FAILURE; } + if( pArea->fTrigger ) + { + if( !hb_dbfTriggerDo( pArea, EVENT_PACK, 0, NULL ) ) + return FAILURE; + } + if( SELF_GOCOLD( ( AREAP ) pArea ) != SUCCESS ) return FAILURE; @@ -3667,6 +3921,12 @@ static ERRCODE hb_dbfZap( DBFAREAP pArea ) return FAILURE; } + if( pArea->fTrigger ) + { + if( !hb_dbfTriggerDo( pArea, EVENT_ZAP, 0, NULL ) ) + return FAILURE; + } + if( SELF_GOCOLD( ( AREAP ) pArea ) != SUCCESS ) return FAILURE; @@ -4527,6 +4787,17 @@ static ERRCODE hb_dbfExit( LPRDDNODE pRDD ) if( pRDD->lpvCargo ) { + LPDBFDATA pData = ( LPDBFDATA ) pRDD->lpvCargo; + + if( pData->szTrigger ) + hb_xfree( pData->szTrigger ); + if( pData->szPendingTrigger ) + hb_xfree( pData->szPendingTrigger ); + if( pData->szPasswd ) + hb_xfree( pData->szPasswd ); + if( pData->szPendingPasswd ) + hb_xfree( pData->szPendingPasswd ); + hb_xfree( pRDD->lpvCargo ); pRDD->lpvCargo = NULL; } @@ -4600,6 +4871,92 @@ static ERRCODE hb_dbfRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, P break; } + case RDDI_TRIGGER: + { + char * szTrigger = pData->szTrigger; + BOOL fFree = FALSE; + + if( HB_IS_STRING( pItem ) ) + { + fFree = TRUE; + pData->szTrigger = hb_itemGetCLen( pItem ) > 0 ? + hb_itemGetC( pItem ) : NULL; + } + + if( fFree && szTrigger ) + hb_itemPutCPtr( pItem, szTrigger, strlen( szTrigger ) ); + else + hb_itemPutC( pItem, szTrigger ); + + if( !szTrigger && !fFree ) + return FAILURE; + + break; + } + case RDDI_PENDINGTRIGGER: + if( HB_IS_STRING( pItem ) ) + { + if( pData->szPendingTrigger ) + { + hb_xfree( pData->szPendingTrigger ); + pData->szPendingTrigger = NULL; + } + if( hb_itemGetCLen( pItem ) > 0 ) + pData->szPendingTrigger = hb_itemGetC( pItem ); + } + else if( pData->szPendingTrigger ) + { + hb_itemPutCPtr( pItem, pData->szPendingTrigger, + strlen( pData->szPendingTrigger ) ); + pData->szPendingTrigger = NULL; + } + else + return FAILURE; + break; + + case RDDI_PASSWORD: + { + char * szPasswd = pData->szPasswd; + BOOL fFree = FALSE; + + if( HB_IS_STRING( pItem ) ) + { + fFree = TRUE; + pData->szPasswd = hb_itemGetCLen( pItem ) > 0 ? + hb_itemGetC( pItem ) : NULL; + } + + if( fFree && szPasswd ) + hb_itemPutCPtr( pItem, szPasswd, strlen( szPasswd ) ); + else + hb_itemPutC( pItem, szPasswd ); + + if( !szPasswd && !fFree ) + return FAILURE; + + break; + } + case RDDI_PENDINGPASSWORD: + if( HB_IS_STRING( pItem ) ) + { + if( pData->szPendingPasswd ) + { + hb_xfree( pData->szPendingPasswd ); + pData->szPendingPasswd = NULL; + } + if( hb_itemGetCLen( pItem ) > 0 ) + pData->szPendingPasswd = hb_itemGetC( pItem ); + } + else if( pData->szPendingPasswd ) + { + hb_itemPutCPtr( pItem, pData->szPendingPasswd, + strlen( pData->szPendingPasswd ) ); + pData->szPendingPasswd = NULL; + } + else + return FAILURE; + break; + default: return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem ); diff --git a/harbour/source/rdd/workarea.c b/harbour/source/rdd/workarea.c index 6bb663566c..b3feff9978 100644 --- a/harbour/source/rdd/workarea.c +++ b/harbour/source/rdd/workarea.c @@ -1680,6 +1680,7 @@ static ERRCODE hb_waRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnection, hb_itemPutC( pItem, hb_set.HB_SET_MFILEEXT ); break; } + /* no break - return FAILURE */ case RDDI_TABLEEXT: case RDDI_ORDBAGEXT: case RDDI_ORDEREXT: