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 );