2007-05-04 15:35 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)

* harbour/contrib/Makefile
  * harbour/contrib/bmdbfcdx/Makefile
  * harbour/source/rdd/Makefile
    ! fixed GNU make compilation

  * harbour/include/hbapifs.h
  * harbour/source/rtl/filesys.c
    + added support for DOS/Windows DENY_* flag emulation in POSIX
      systems using BSD locks. So far such emulatin was done with
      standard POSIX locks. The new emulation can be enabled by setting
      HB_USE_BSDLOCKS and disabled by HB_USE_BSDLOCKS_OFF. By default
      it's enabled in Linux and BSD* based systems.
      Please not that it BSD locks work in differ way then POSIX ones.
      They are bound with file handle and process ID not i-node and PID.
      It will allow to synchronize even single process but it will not
      work in NFS and some old BSD and Linux kernels. This synchronization
      cannot be used also between different platforms. If someone needs
      such synchronization then he should build Harbour on all platforms
      with HB_USE_BSDLOCKS_OFF and HB_USE_SHARELOCKS with valid multi
      platform lock offset

  * harbour/source/rdd/dbcmd.c
    * removed all explicit NETERR setting - now it can be set only
      by NETERR() function (executed by default errorsys)
    * changed ordListAdd()/dbSetIndex() - now they return logical value
      with information about success

  * harbour/source/rdd/wafunc.c
    * changed hb_rddOpenTable()/hb_rddCreateTable() to make dbUseArea()/
      dbCreate() more Clipper compatible - it's not exact Clipper behavior
      but I intentionally do not want to replicate some strange for me
      things, f.e. I do not know why Clipper ignores RDDNAME when it has
      only one character

  + harbour/tests/tstuse.prg
    + test code for dbUseArea()
This commit is contained in:
Przemyslaw Czerpak
2007-05-04 13:36:02 +00:00
parent 71af9421c6
commit d1f8cc8478
9 changed files with 158 additions and 78 deletions

View File

@@ -8,6 +8,44 @@
2002-12-01 13:30 UTC+0100 Foo Bar <foo.bar@foobar.org>
*/
2007-05-04 15:35 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/contrib/Makefile
* harbour/contrib/bmdbfcdx/Makefile
* harbour/source/rdd/Makefile
! fixed GNU make compilation
* harbour/include/hbapifs.h
* harbour/source/rtl/filesys.c
+ added support for DOS/Windows DENY_* flag emulation in POSIX
systems using BSD locks. So far such emulatin was done with
standard POSIX locks. The new emulation can be enabled by setting
HB_USE_BSDLOCKS and disabled by HB_USE_BSDLOCKS_OFF. By default
it's enabled in Linux and BSD* based systems.
Please not that it BSD locks work in differ way then POSIX ones.
They are bound with file handle and process ID not i-node and PID.
It will allow to synchronize even single process but it will not
work in NFS and some old BSD and Linux kernels. This synchronization
cannot be used also between different platforms. If someone needs
such synchronization then he should build Harbour on all platforms
with HB_USE_BSDLOCKS_OFF and HB_USE_SHARELOCKS with valid multi
platform lock offset
* harbour/source/rdd/dbcmd.c
* removed all explicit NETERR setting - now it can be set only
by NETERR() function (executed by default errorsys)
* changed ordListAdd()/dbSetIndex() - now they return logical value
with information about success
* harbour/source/rdd/wafunc.c
* changed hb_rddOpenTable()/hb_rddCreateTable() to make dbUseArea()/
dbCreate() more Clipper compatible - it's not exact Clipper behavior
but I intentionally do not want to replicate some strange for me
things, f.e. I do not know why Clipper ignores RDDNAME when it has
only one character
+ harbour/tests/tstuse.prg
+ test code for dbUseArea()
2007-05-04 11:06 UTC+0100 Miguel Angel Marchuet (miguelangel/at/marchuet.net)
* source/rdd/wafunc.c
* change of the behavior of DbUseArea opening, so that one behaves like made Clipper, when it fails the

View File

@@ -12,7 +12,7 @@ DIRS=\
libmisc \
libnf \
samples \
bmdbfcdx \
bmdbfcdx \
ifeq ($(HB_ARCHITECTURE),w32)

View File

@@ -2,11 +2,11 @@
# $Id$
#
ROOT = ../../../
ROOT = ../../
C_SOURCES=\
bmdbfcdx1.c \
bmsixcdx1.c
bmsixcdx1.c
LIBNAME=bmdbfcdx

View File

@@ -152,6 +152,12 @@ extern HB_EXPORT FHANDLE hb_fsGetOsHandle( FHANDLE hFileHandle );
# define HB_USE_SHARELOCKS
# define HB_SHARELOCK_POS 0x7fffffffUL
# define HB_SHARELOCK_SIZE 0x1UL
# if defined( HB_USE_BSDLOCKS_OFF )
# undef HB_USE_BSDLOCKS
# elif ( defined( HB_OS_LINUX ) || defined( HB_OS_BSD ) ) && \
!defined( __WATCOMC__ ) && !defined( HB_USE_BSDLOCKS )
# define HB_USE_BSDLOCKS
# endif
#endif
#define HB_MAX_DRIVE_LENGTH 10

View File

@@ -37,7 +37,7 @@ LIBNAME=rdd
# The list of all valid DB drivers is defined in config/global.cf.
DIRS=$(HB_DB_DRIVERS)
DIRS=nulsys $(HB_DB_DRIVERS)
include $(TOP)$(ROOT)config/lib.cf
include $(TOP)$(ROOT)config/dir.cf

View File

@@ -269,17 +269,10 @@ HB_FUNC( DBAPPEND )
BOOL bUnLockAll = ISLOG( 1 ) ? hb_parl( 1 ) : TRUE;
ERRCODE errCode;
/* Clipper clears NETERR flag when table is open */
/* Clipper clears NETERR flag before APPEND */
hb_rddSetNetErr( FALSE );
errCode = SELF_APPEND( pArea, bUnLockAll );
hb_retl( errCode == SUCCESS );
/*
* Warning: this is not Clipper compatible. NETERR() should be set by
* error handler not here
*/
if( errCode != SUCCESS )
hb_rddSetNetErr( TRUE );
}
else
hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBAPPEND" );
@@ -361,7 +354,7 @@ HB_FUNC( DBCREATE )
#ifdef HB_C52_STRICT
hb_arrayLen( pStruct ) == 0 ||
#endif
!szFileName || !szFileName[ 0 ] )
!szFileName )
{
hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, "DBCREATE" );
return;
@@ -1765,7 +1758,7 @@ HB_FUNC( ORDLISTADD )
DBORDERINFO pOrderInfo;
ERRCODE errCode;
/* Clipper clears NETERR flag when table is open */
/* Clipper clears NETERR flag when index is open */
hb_rddSetNetErr( FALSE );
memset( &pOrderInfo, 0, sizeof( DBORDERINFO ) );
@@ -1783,14 +1776,12 @@ HB_FUNC( ORDLISTADD )
errCode = SELF_ORDLSTADD( pArea, &pOrderInfo );
/*
* Warning: this is not Clipper compatible. NETERR() should be set by
* error handler not here
*/
if( errCode != SUCCESS )
hb_rddSetNetErr( TRUE );
if( HB_IS_NIL( pOrderInfo.itmResult ) )
hb_retl( errCode == SUCCESS );
else
hb_itemReturn( pOrderInfo.itmResult );
hb_itemRelease( hb_itemReturn( pOrderInfo.itmResult ) );
hb_itemRelease( pOrderInfo.itmResult );
}
else
hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDLISTADD" );

View File

@@ -578,47 +578,57 @@ ERRCODE hb_rddOpenTable( const char * szFileName, const char * szDriver,
char szDriverBuffer[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ];
DBOPENINFO pInfo;
ERRCODE errCode;
//USHORT uiPrevArea;
AREAP pArea;
/* Clipper clears NETERR flag before RT error below */
/* uiArea = 0 in hb_rddInsertAreaNode() means chose first
* available free area, otherwise we should close table in
* current WA and it should be done before parameter validation
* RT errors below. This breaks xHarbour like MT code which
* shares WA between threads so dbUseArea() should be covered
* by external mutex to make lNewArea MT safe, [druzus]
*/
if( uiArea )
{
hb_rddSelectWorkAreaNumber( uiArea );
hb_rddReleaseCurrentArea();
}
else
hb_rddSelectFirstAvailable();
/* Clipper clears NETERR flag before parameter validation, [druzus]
*/
hb_rddSetNetErr( FALSE );
if( !szFileName || !szFileName[ 0 ] )
{
hb_errRT_DBCMD( EG_ARG, EDBCMD_USE_BADPARAMETER, NULL, "DBUSEAREA" );
return FAILURE;
}
/* Now check parameters, first RDD name.
* Clipper seems to make sth like:
* if( szDriver && strlen( szDriver ) > 1 )
* but I do not think we should replicate it, [druzus]
*/
if( szDriver && szDriver[ 0 ] )
{
hb_strncpyUpper( szDriverBuffer, szDriver, HARBOUR_MAX_RDD_DRIVERNAME_LENGTH );
szDriver = szDriverBuffer;
}
else
{
szDriver = hb_rddDefaultDrv( NULL );
}
//uiPrevArea = hb_rddGetCurrentWorkAreaNumber();
/*
* 0 means chose first available in hb_rddInsertAreaNode()
* This hack is necessary to avoid race condition in MT
* if we don't want to lock whole RDD subsystem, Druzus
*/
hb_rddSelectWorkAreaNumber( uiArea );
if( uiArea )
{
hb_rddReleaseCurrentArea();
}
/* Create a new WorkArea node */
/* First try to create new are node and validate RDD name */
if( ! hb_rddInsertAreaNode( szDriver ) )
{
hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBUSEAREA" );
return FAILURE;
}
/* Then check if valid file name was given - Clipper allows to use empty
* ("") file name
*/
if( !szFileName )
{
hb_rddReleaseCurrentArea();
hb_errRT_DBCMD( EG_ARG, EDBCMD_USE_BADPARAMETER, NULL, "DBUSEAREA" );
return FAILURE;
}
pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();
/* Fill pInfo structure */
@@ -631,42 +641,18 @@ ERRCODE hb_rddOpenTable( const char * szFileName, const char * szDriver,
pInfo.ulConnection = ulConnection;
pInfo.lpdbHeader = NULL;
if( pStruct )
{
errCode = SELF_CREATEFIELDS( pArea, pStruct );
}
else
{
errCode = SUCCESS;
}
errCode = pStruct ? SELF_CREATEFIELDS( pArea, pStruct ) : SUCCESS;
if( errCode == SUCCESS )
{
if( pDelim && !HB_IS_NIL( pDelim ) )
errCode = SELF_INFO( pArea, DBI_SETDELIMITER, pDelim );
if( errCode == SUCCESS )
{
/* Open file */
errCode = SELF_OPEN( pArea, &pInfo );
/*-----------------04/05/2007 11:00-----------------
* Clipper not restore the old workarea
* --------------------------------------------------*/
/*
if( errCode != SUCCESS )
{
hb_rddReleaseCurrentArea();
hb_rddSelectWorkAreaNumber( uiPrevArea );
}*/
}
}
/*
* Warning: this is not Clipper compatible. NETERR() should be set by
* error handler not here
*/
if( errCode != SUCCESS )
hb_rddSetNetErr( TRUE );
hb_rddReleaseCurrentArea();
return errCode;
}
@@ -683,7 +669,7 @@ ERRCODE hb_rddCreateTable( const char * szFileName, const char * szDriver,
USHORT uiPrevArea;
AREAP pArea;
if( !szFileName || !szFileName[ 0 ] )
if( !szFileName )
{
hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, "DBCREATE" );
return FAILURE;
@@ -695,27 +681,25 @@ ERRCODE hb_rddCreateTable( const char * szFileName, const char * szDriver,
szDriver = szDriverBuffer;
}
else
{
szDriver = hb_rddDefaultDrv( NULL );
}
uiPrevArea = hb_rddGetCurrentWorkAreaNumber();
/*
* 0 means chose first available in hb_rddInsertAreaNode()
* This hack is necessary to avoid race condition in MT
* if we don't want to lock whole RDD subsystem, Druzus
* mode where workareas are shared between threads and
* we don't want to lock whole RDD subsystem, [druzus]
*/
hb_rddSelectWorkAreaNumber( uiArea );
if( uiArea )
{
hb_rddReleaseCurrentArea();
}
/* Create a new WorkArea node */
if( ! hb_rddInsertAreaNode( szDriver ) )
{
hb_errRT_DBCMD( EG_CREATE, EDBCMD_BADPARAMETER, NULL, "DBCREATE" );
hb_rddSelectWorkAreaNumber( uiPrevArea );
hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBCREATE" );
return FAILURE;
}
pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();

View File

@@ -185,6 +185,9 @@
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
#endif
#if defined( HB_USE_SHARELOCKS ) && defined( HB_USE_BSDLOCKS )
#include <sys/file.h>
#endif
/* 27/08/2004 - <maurilio.longo@libero.it>
HB_FS_GETDRIVE() should return a number in the range 0..25 ('A'..'Z')
@@ -2230,6 +2233,15 @@ HB_EXPORT FHANDLE hb_fsExtOpen( BYTE * pFilename, BYTE * pDefExt,
#if defined( HB_USE_SHARELOCKS )
if( hFile != FS_ERROR && uiExFlags & FXO_SHARELOCK )
{
#if defined( HB_USE_BSDLOCKS )
int iLock;
if( ( uiFlags & ( FO_READ | FO_WRITE | FO_READWRITE ) ) == FO_READ ||
( uiFlags & ( FO_DENYREAD | FO_DENYWRITE | FO_EXCLUSIVE ) ) == 0 )
iLock = LOCK_SH | LOCK_NB;
else
iLock = LOCK_EX | LOCK_NB;
if( flock( hFile, iLock ) != 0 )
#else
USHORT uiLock;
if( ( uiFlags & ( FO_READ | FO_WRITE | FO_READWRITE ) ) == FO_READ ||
( uiFlags & ( FO_DENYREAD | FO_DENYWRITE | FO_EXCLUSIVE ) ) == 0 )
@@ -2238,6 +2250,7 @@ HB_EXPORT FHANDLE hb_fsExtOpen( BYTE * pFilename, BYTE * pDefExt,
uiLock = FL_LOCK | FLX_EXCLUSIVE;
if( !hb_fsLockLarge( hFile, HB_SHARELOCK_POS, HB_SHARELOCK_SIZE, uiLock ) )
#endif
{
hb_fsClose( hFile );
hFile = FS_ERROR;

48
harbour/tests/tstuse.prg Normal file
View File

@@ -0,0 +1,48 @@
/*
* $Id$
*/
#define EOL chr(13)+chr(10)
#command ? [<x,...>] => outstd(EOL)[;outstd(<x>)]
proc main()
? OS(), VERSION()
if !file("_tst.dbf")
dbCreate("_tst",{{"F1","C",1,0}})
endif
if !file("_tst2.dbf")
dbCreate("_tst2",{{"F1","C",1,0}})
endif
USE _tst NEW ALIAS "ONE" EXCLUSIVE
? select(), alias(), netErr(), used()
?
mkTest( .T., "NORDD",, "TWO", .T., .F. )
mkTest( .T., "DBF",, "TWO", .T., .F. )
mkTest( .T., "DBF", "", "TWO", .T., .F. )
mkTest( .T., "DBF", "nofile", "TWO", .T., .F. )
mkTest( .T., "DBF", "_tst2", "ONE", .T., .F. )
mkTest( .T., "DBF", "_tst", "ONE", .T., .F. )
mkTest( .T., "DBF", "_tst", "TWO", .T., .F. )
?
dbUseArea( .T., "DBF", "_tst", "ONE", .T., .F. )
? select(), alias(), netErr(), used()
dbUseArea( .T., "DBF", "_tst", "TWO", .T., .F. )
? select(), alias(), netErr(), used()
?
dbSelectArea( 1 )
mkTest( .F., "NORDD",, "TWO", .T., .F. )
?
return
proc mkTest( lNewArea, cRdd, cFile, cAlias, lShared, lReadOnly )
local cbErr:=errorBlock({|oErr|break(oErr)}), oErr
netErr(.f.)
begin sequence
dbUseArea( lNewArea, cRdd, cFile, cAlias, lShared, lReadOnly )
recover using oErr
? "Error:", oErr:subCode, oErr:description, oErr:operation, oErr:osCode
end
? select(), alias(), netErr(), used()
errorBlock(cbErr)
return