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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 );
|
||||
|
||||
Reference in New Issue
Block a user