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:
Przemysław Czerpak
2015-03-05 20:46:23 +01:00
parent 6df9526b8d
commit 74c4b51266
7 changed files with 192 additions and 15 deletions

View File

@@ -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

View File

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

View File

@@ -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,

View File

@@ -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

View File

@@ -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;
}

View File

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

View File

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