From 74c4b51266b8857b943590c4c8d5d181fedde8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Czerpak?= Date: Thu, 5 Mar 2015 20:46:23 +0100 Subject: [PATCH] 2015-03-05 20:46 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * include/hbapi.h * src/vm/garbage.c + added hb_gcDummyClear() function * include/hbapirdd.h * include/hbusrrdd.ch + added DBTF_CPYCTR constant value - when set in dbTransInfo.uiFlags then after record transfer field counters should to be copied from source to destination area * include/hbapirdd.h * src/rdd/wafunc.c + added new C functions hb_dbTransInfoPut() and hb_dbTransInfoGet() which allow to store and retrieve pointer to DBTRANSINFO structure into/from HB_ITEM with strict type verification. * src/rdd/wafunc.c * pass pointer to DBTRANSINFO structure as argument of DBI_TRANSREC action. It allows RDD serving destination area to decide which fields and how should be transferred updating uiFlags, uiItemCount and lpTransItems members of DBTRANSINFO. If RDD removes all fields from DBTRANSINFO structure (uiItemCount==0) or does not return HB_SUCCESS for DBI_TRANSREC action (default WA implementation returns HB_SUCCESS so it's not necessary to overload it if RDD does not make any additional operations) then record transfer is interrupted. * copy field counters only when destination area asked about it setting DBTF_CPYCTR in dbTransInfo.uiFlags in DBI_TRANSREC action. * src/rdd/dbf1.c * do not copy automatically updated fields when destination area is not empty * set DBTF_CPYCTR to indicate that counters should be copied from source to destination area when original value of automatically updated fields are transferred ; Now DBF* RDDs in Harbour respects the following rules for record transfer operations (COPY TO / APPEND FROM) with automatically updated fields: - COPY TO transfers original values to destination table and finally copy counters from the source table to destination one so autoincrement fields in both tables after next append will be initialized with the same values regardless of number of copied records - even if only single record is copied then counters in destination table will inherit next values for new record from the source table. Also values of RowVer and ModTime fields are copied from source to destination table and not updated during transfer operation. - APPEND FROM works like COPY TO (original field values and then counters are copied to destination table) if the source table supports counters and destination table is empty and FLocked() or opened in exclusive mode. If source table does not support counters for given fields, i.e. it is processed by transfer RDD like DELIM or SDF (RDT_TRANSFER) or destination table is not empty or opened in shared mode and FLock is not set when APPEND FROM is executed then automatically updated fields (counters, RowVer, ModTime) are not copied and initialized with new values like for each new record added to destination table. * ChangeLog.txt ! typo in last ChangeLog entry --- ChangeLog.txt | 65 ++++++++++++++++++++++++++++++++++++- include/hbapi.h | 1 + include/hbapirdd.h | 3 ++ include/hbusrrdd.ch | 1 + src/rdd/dbf1.c | 78 +++++++++++++++++++++++++++++++++++++++++++++ src/rdd/wafunc.c | 54 +++++++++++++++++++++++-------- src/vm/garbage.c | 5 +++ 7 files changed, 192 insertions(+), 15 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 3eb4554109..7de1032cda 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,69 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2015-03-05 20:46 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * include/hbapi.h + * src/vm/garbage.c + + added hb_gcDummyClear() function + + * include/hbapirdd.h + * include/hbusrrdd.ch + + added DBTF_CPYCTR constant value - when set in dbTransInfo.uiFlags + then after record transfer field counters should to be copied from + source to destination area + + * include/hbapirdd.h + * src/rdd/wafunc.c + + added new C functions hb_dbTransInfoPut() and hb_dbTransInfoGet() + which allow to store and retrieve pointer to DBTRANSINFO structure + into/from HB_ITEM with strict type verification. + + * src/rdd/wafunc.c + * pass pointer to DBTRANSINFO structure as argument of DBI_TRANSREC + action. It allows RDD serving destination area to decide which + fields and how should be transferred updating uiFlags, uiItemCount + and lpTransItems members of DBTRANSINFO. + If RDD removes all fields from DBTRANSINFO structure (uiItemCount==0) + or does not return HB_SUCCESS for DBI_TRANSREC action (default WA + implementation returns HB_SUCCESS so it's not necessary to overload + it if RDD does not make any additional operations) then record + transfer is interrupted. + * copy field counters only when destination area asked about it setting + DBTF_CPYCTR in dbTransInfo.uiFlags in DBI_TRANSREC action. + + * src/rdd/dbf1.c + * do not copy automatically updated fields when destination area + is not empty + * set DBTF_CPYCTR to indicate that counters should be copied from + source to destination area when original value of automatically + updated fields are transferred + ; Now DBF* RDDs in Harbour respects the following rules for record + transfer operations (COPY TO / APPEND FROM) with automatically + updated fields: + - COPY TO transfers original values to destination table and + finally copy counters from the source table to destination one + so autoincrement fields in both tables after next append will be + initialized with the same values regardless of number of copied + records - even if only single record is copied then counters in + destination table will inherit next values for new record from + the source table. Also values of RowVer and ModTime fields are + copied from source to destination table and not updated during + transfer operation. + - APPEND FROM works like COPY TO (original field values and then + counters are copied to destination table) if the source table + supports counters and destination table is empty and FLocked() + or opened in exclusive mode. + If source table does not support counters for given fields, i.e. + it is processed by transfer RDD like DELIM or SDF (RDT_TRANSFER) + or destination table is not empty or opened in shared mode and + FLock is not set when APPEND FROM is executed then automatically + updated fields (counters, RowVer, ModTime) are not copied and + initialized with new values like for each new record added to + destination table. + + * ChangeLog.txt + ! typo in last ChangeLog entry + 2015-03-04 11:18 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * include/hbapi.h ! fixed HB_ISMEMO() macro, original version was accepting the same @@ -30,7 +93,7 @@ ! protection against GPF when wrong parameters are passed to __dbArrange() + added support for transferring records using __dbArrange() to area with different fields order (low level driver may refuse to finish such - operation but not it's possible. + operation but now it's possible. 2015-03-03 16:26 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * contrib/rddads/ads1.c diff --git a/include/hbapi.h b/include/hbapi.h index 1f8c3b8609..f87742e00f 100644 --- a/include/hbapi.h +++ b/include/hbapi.h @@ -599,6 +599,7 @@ extern HB_EXPORT void hb_gcMark( void * pAlloc ); /* mark given block as us extern HB_EXPORT void hb_gcRefInc( void * pAlloc ); /* increment reference counter */ extern HB_EXPORT void hb_gcRefFree( void * pAlloc ); /* decrement reference counter and free the block when 0 reached */ +extern HB_EXPORT void hb_gcDummyClear( void * Cargo ); /* dummy GC clear function */ extern HB_EXPORT void hb_gcDummyMark( void * Cargo ); /* dummy GC mark function */ extern PHB_ITEM hb_gcGripGet( PHB_ITEM pItem ); diff --git a/include/hbapirdd.h b/include/hbapirdd.h index 03c2c639b2..b817d824a0 100644 --- a/include/hbapirdd.h +++ b/include/hbapirdd.h @@ -125,6 +125,7 @@ HB_EXTERN_BEGIN #define DBTF_MATCH 0x0001 #define DBTF_PUTREC 0x0002 +#define DBTF_CPYCTR 0x0004 @@ -1208,6 +1209,8 @@ extern HB_EXPORT HB_ERRCODE hb_rddCreateTableTemp( const char * szCpId, HB_ULONG ulConnection, PHB_ITEM pStruct ); extern HB_EXPORT HB_ERRCODE hb_dbTransCounters( LPDBTRANSINFO lpdbTransInfo ); +extern HB_EXPORT PHB_ITEM hb_dbTransInfoPut( PHB_ITEM pItem, LPDBTRANSINFO lpdbTransInfo ); +extern HB_EXPORT LPDBTRANSINFO hb_dbTransInfoGet( PHB_ITEM pItem ); extern HB_EXPORT HB_ERRCODE hb_dbTransStruct( AREAP lpaSource, AREAP lpaDest, LPDBTRANSINFO lpdbTransInfo, diff --git a/include/hbusrrdd.ch b/include/hbusrrdd.ch index 18f064cab1..466b0a06a1 100644 --- a/include/hbusrrdd.ch +++ b/include/hbusrrdd.ch @@ -202,6 +202,7 @@ /* Flags for DBTRANSINFO */ #define DBTF_MATCH 0x0001 #define DBTF_PUTREC 0x0002 +#define DBTF_CPYCTR 0x0004 /* Codes for Locking methods */ #define DBLM_EXCLUSIVE 1 diff --git a/src/rdd/dbf1.c b/src/rdd/dbf1.c index ba62e0b6c7..2c36ff5741 100644 --- a/src/rdd/dbf1.c +++ b/src/rdd/dbf1.c @@ -279,6 +279,71 @@ static int hb_dbfNextValueStep( DBFAREAP pArea, HB_USHORT uiField, int iStep ) return iPrevStep; } +void hb_dbfTransCheckCounters( LPDBTRANSINFO lpdbTransInfo ) +{ + HB_BOOL fCopyCtr = HB_TRUE; + HB_USHORT uiCount, uiDest; + DBFAREAP pArea = ( DBFAREAP ) lpdbTransInfo->lpaDest; + + if( pArea->ulRecCount > 0 || ( pArea->fShared && ! pArea->fFLocked ) ) + fCopyCtr = HB_FALSE; + else + { + PHB_ITEM pItem = NULL; + + /* check if counters can be copied for all fields */ + for( uiCount = 0; uiCount < lpdbTransInfo->uiItemCount; ++uiCount ) + { + HB_USHORT uiField = lpdbTransInfo->lpTransItems[ uiCount ].uiDest; + LPFIELD pField = lpdbTransInfo->lpaDest->lpFields + uiField - 1; + + if( hb_dbfIsAutoIncField( pField ) != HB_AUTOINC_NONE ) + { + if( pItem == NULL ) + pItem = hb_itemNew( NULL ); + if( SELF_FIELDINFO( lpdbTransInfo->lpaSource, + lpdbTransInfo->lpTransItems[ uiCount ].uiSource, + DBS_COUNTER, pItem ) != HB_SUCCESS ) + { + fCopyCtr = HB_FALSE; + break; + } + } + } + if( pItem != NULL ) + hb_itemRelease( pItem ); + } + + if( fCopyCtr ) + lpdbTransInfo->uiFlags |= DBTF_CPYCTR; + else + { + for( uiCount = uiDest = 0; uiCount < lpdbTransInfo->uiItemCount; ++uiCount ) + { + HB_USHORT uiField = lpdbTransInfo->lpTransItems[ uiCount ].uiDest; + LPFIELD pField = lpdbTransInfo->lpaDest->lpFields + uiField - 1; + + if( hb_dbfIsAutoIncField( pField ) == HB_AUTOINC_NONE && + pField->uiType != HB_FT_MODTIME ) + { + if( uiDest != uiCount ) + { + lpdbTransInfo->lpTransItems[ uiDest ].uiSource = + lpdbTransInfo->lpTransItems[ uiCount ].uiSource; + lpdbTransInfo->lpTransItems[ uiDest ].uiDest = + lpdbTransInfo->lpTransItems[ uiCount ].uiDest; + } + ++uiDest; + } + } + if( uiDest < uiCount ) + { + lpdbTransInfo->uiItemCount = uiDest; + lpdbTransInfo->uiFlags &= ~( DBTF_MATCH | DBTF_PUTREC ); + } + } +} + static void hb_dbfUpdateStampFields( DBFAREAP pArea ) { long lJulian = 0, lMilliSec = 0; @@ -3592,6 +3657,19 @@ static HB_ERRCODE hb_dbfInfo( DBFAREAP pArea, HB_USHORT uiIndex, PHB_ITEM pItem if( HB_IS_LOGICAL( pItem ) ) pArea->fTransRec = hb_itemGetL( pItem ); + else if( HB_IS_POINTER( pItem ) ) + { + LPDBTRANSINFO lpdbTransInfo = hb_dbTransInfoGet( pItem ); + + if( lpdbTransInfo ) + { + if( pArea->fShared && pArea->fFLocked ) + pArea->ulRecCount = hb_dbfCalcRecCount( pArea ); + + hb_dbfTransCheckCounters( lpdbTransInfo ); + pArea->fTransRec = HB_TRUE; + } + } hb_itemPutL( pItem, fTransRec ); break; } diff --git a/src/rdd/wafunc.c b/src/rdd/wafunc.c index cd84b013a5..d8fe392d14 100644 --- a/src/rdd/wafunc.c +++ b/src/rdd/wafunc.c @@ -859,13 +859,36 @@ static const char * hb_dbTransFieldPos( PHB_ITEM pFields, HB_USHORT uiField ) return szField; } +static const HB_GC_FUNCS s_gcTransInfo = +{ + hb_gcDummyClear, + hb_gcDummyMark +}; + +PHB_ITEM hb_dbTransInfoPut( PHB_ITEM pItem, LPDBTRANSINFO lpdbTransInfo ) +{ + LPDBTRANSINFO * pHolder; + + pHolder = ( LPDBTRANSINFO * ) hb_gcAllocate( sizeof( LPDBTRANSINFO ), &s_gcTransInfo ); + *pHolder = lpdbTransInfo; + + return hb_itemPutPtrGC( pItem, pHolder ); +} + +LPDBTRANSINFO hb_dbTransInfoGet( PHB_ITEM pItem ) +{ + LPDBTRANSINFO * pHolder = ( LPDBTRANSINFO * ) hb_itemGetPtrGC( pItem, &s_gcTransInfo ); + + return pHolder ? * pHolder : NULL; +} + /* update counters for autoinc and rowver fields */ HB_ERRCODE hb_dbTransCounters( LPDBTRANSINFO lpdbTransInfo ) { PHB_ITEM pItem = hb_itemNew( NULL ); HB_USHORT uiCount; - for( uiCount = 1; uiCount <= lpdbTransInfo->uiItemCount; ++uiCount ) + for( uiCount = 0; uiCount < lpdbTransInfo->uiItemCount; ++uiCount ) { LPDBTRANSITEM lpdbTransItem = &lpdbTransInfo->lpTransItems[ uiCount ]; @@ -1102,7 +1125,6 @@ HB_ERRCODE hb_rddTransRecords( AREAP pArea, PHB_ITEM pStruct = NULL; DBTRANSINFO dbTransInfo; HB_USHORT uiPrevArea, uiCount, uiSwap; - HB_BOOL fUpdateCtr = HB_FALSE; HB_ERRCODE errCode; memset( &dbTransInfo, 0, sizeof( dbTransInfo ) ); @@ -1122,11 +1144,8 @@ HB_ERRCODE hb_rddTransRecords( AREAP pArea, HB_TRUE, szCpId, ulConnection, pStruct, pDelim ); if( errCode == HB_SUCCESS ) - { - fUpdateCtr = HB_TRUE; dbTransInfo.lpaDest = lpaClose = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); - } } } else @@ -1201,15 +1220,22 @@ HB_ERRCODE hb_rddTransRecords( AREAP pArea, dbTransInfo.dbsci.fIgnoreDuplicates = HB_FALSE; dbTransInfo.dbsci.fBackward = HB_FALSE; - pTransItm = hb_itemPutL( NULL, HB_TRUE ); - SELF_INFO( dbTransInfo.lpaDest, DBI_TRANSREC, pTransItm ); - - errCode = SELF_TRANS( dbTransInfo.lpaSource, &dbTransInfo ); - - SELF_INFO( dbTransInfo.lpaDest, DBI_TRANSREC, pTransItm ); - - if( errCode == HB_SUCCESS && fUpdateCtr ) - errCode = hb_dbTransCounters( &dbTransInfo ); + pTransItm = hb_dbTransInfoPut( NULL, &dbTransInfo ); + errCode = SELF_INFO( dbTransInfo.lpaDest, DBI_TRANSREC, pTransItm ); + if( errCode == HB_SUCCESS ) + { + errCode = dbTransInfo.uiItemCount == 0 ? HB_FAILURE : + SELF_TRANS( dbTransInfo.lpaSource, &dbTransInfo ); + /* we always call DBI_TRANSREC second time after TRANS() method + * even if TRANS() failed - it's for RDDs which may need to store + * pointer to dbTransInfo in first call and then release it and/or + * clean some structures allocated for transfer operation [druzus] + */ + SELF_INFO( dbTransInfo.lpaDest, DBI_TRANSREC, pTransItm ); + if( errCode == HB_SUCCESS && ( dbTransInfo.uiFlags & DBTF_CPYCTR ) ) + errCode = hb_dbTransCounters( &dbTransInfo ); + } + hb_itemRelease( pTransItm ); } if( dbTransInfo.lpTransItems ) diff --git a/src/vm/garbage.c b/src/vm/garbage.c index 264f127f16..f5ca49c945 100644 --- a/src/vm/garbage.c +++ b/src/vm/garbage.c @@ -334,6 +334,11 @@ HB_COUNTER hb_gcRefCount( void * pBlock ) } +HB_GARBAGE_FUNC( hb_gcDummyClear ) +{ + HB_SYMBOL_UNUSED( Cargo ); +} + HB_GARBAGE_FUNC( hb_gcDummyMark ) { HB_SYMBOL_UNUSED( Cargo );