* source/rtl/gtwvt/gtwvt.c
! Fixed maximized window size.
* contrib/hbw32/dllcall.c
* Further cleanup.
! MessageBox()es converted to RTE calls.
* contrib/hbcurl/hbcurl.c
* contrib/rddads/ads1.c
* contrib/rddads/adsfunc.c
* source/rdd/dbcmd.c
* source/rdd/dbcmd53.c
* source/rdd/dbcmdx.c
* source/rdd/dbsql.c
* source/rdd/wafunc.c
* source/rdd/workarea.c
* source/rtl/abs.c
* source/rtl/at.c
* source/rtl/cdpapi.c
* source/rtl/chrasc.c
* source/rtl/copyfile.c
* source/rtl/datec.c
* source/rtl/dateshb.c
* source/rtl/do.c
* source/rtl/gtfunc.c
* source/rtl/hbadler.c
* source/rtl/hbbit.c
* source/rtl/hbcrc.c
* source/rtl/hbhex.c
* source/rtl/hbinet.c
* source/rtl/hbregex.c
* source/rtl/hbregexc.c
* source/rtl/hbrunfun.c
* source/rtl/hbtoken.c
* source/rtl/hbzlib.c
* source/rtl/left.c
* source/rtl/len.c
* source/rtl/math.c
* source/rtl/minmax.c
* source/rtl/philes.c
* source/rtl/philesx.c
* source/rtl/replic.c
* source/rtl/round.c
* source/rtl/run.c
* source/rtl/set.c
* source/rtl/space.c
* source/rtl/str.c
* source/rtl/strcase.c
* source/rtl/strpeek.c
* source/rtl/strtran.c
* source/rtl/strzero.c
* source/rtl/substr.c
* source/rtl/transfrm.c
* source/rtl/trim.c
* source/rtl/type.c
* source/rtl/val.c
* source/rtl/valtype.c
* source/rtl/word.c
* source/vm/arrayshb.c
* source/vm/classes.c
* source/vm/debug.c
* source/vm/eval.c
* source/vm/evalhb.c
* source/vm/hashfunc.c
* source/vm/memvars.c
* source/vm/runner.c
* &hb_errFuncName -> HB_ERR_FUNCNAME
% Using HB_ERR_FUNCNAME wherever possible.
1136 lines
31 KiB
C
1136 lines
31 KiB
C
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* Default RDD module
|
|
*
|
|
* Copyright 1999 Bruno Cantero <bruno@issnet.net>
|
|
* Copyright 2007 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
#include "hbapi.h"
|
|
#include "hbapirdd.h"
|
|
#include "hbapiitm.h"
|
|
#include "hbapierr.h"
|
|
#include "hbvm.h"
|
|
#include "rddsys.ch"
|
|
|
|
/*
|
|
* check if a given name can be used as alias expression
|
|
*/
|
|
HB_EXPORT ERRCODE hb_rddVerifyAliasName( const char * szAlias )
|
|
{
|
|
char c;
|
|
|
|
if( szAlias )
|
|
{
|
|
/* Clipper ignores only trailing spaces */
|
|
#if 0
|
|
while( *szAlias == ' ' )
|
|
szAlias++;
|
|
#endif
|
|
|
|
c = *szAlias;
|
|
if( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) || c == '_' )
|
|
{
|
|
c = *(++szAlias);
|
|
while( c != 0 )
|
|
{
|
|
if( c != '_' && ! ( c >= '0' && c <= '9' ) &&
|
|
! ( c >= 'A' && c <= 'Z' ) && ! ( c >= 'a' && c <= 'z' ) )
|
|
{
|
|
if( c == ' ' )
|
|
{
|
|
while( *(++szAlias) == ' ' ) { ; }
|
|
if( ! *szAlias )
|
|
break;
|
|
}
|
|
return FAILURE;
|
|
}
|
|
c = *(++szAlias);
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
return FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Prepares a new WorkArea node.
|
|
*/
|
|
HB_EXPORT void * hb_rddNewAreaNode( LPRDDNODE pRddNode, USHORT uiRddID )
|
|
{
|
|
AREAP pArea;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddNewAreaNode(%p,%hu)", pRddNode, uiRddID));
|
|
|
|
if( pRddNode->uiAreaSize == 0 ) /* Calculate the size of WorkArea */
|
|
{
|
|
USHORT uiSize;
|
|
|
|
pArea = ( AREAP ) hb_xgrab( sizeof( AREA ) );
|
|
memset( pArea, 0, sizeof( AREA ) );
|
|
pArea->lprfsHost = &pRddNode->pTable;
|
|
pArea->rddID = uiRddID;
|
|
|
|
if( SELF_STRUCTSIZE( pArea, &uiSize ) != SUCCESS )
|
|
return NULL;
|
|
|
|
/* Need more space? */
|
|
if( uiSize > sizeof( AREA ) ) /* Size of Area changed */
|
|
{
|
|
pArea = ( AREAP ) hb_xrealloc( pArea, uiSize );
|
|
memset( pArea, 0, uiSize );
|
|
pArea->lprfsHost = &pRddNode->pTable;
|
|
pArea->rddID = uiRddID;
|
|
}
|
|
|
|
pRddNode->uiAreaSize = uiSize; /* Update the size of WorkArea */
|
|
}
|
|
else
|
|
{
|
|
pArea = ( AREAP ) hb_xgrab( pRddNode->uiAreaSize );
|
|
memset( pArea, 0, pRddNode->uiAreaSize );
|
|
pArea->lprfsHost = &pRddNode->pTable;
|
|
pArea->rddID = uiRddID;
|
|
}
|
|
|
|
if( SELF_NEW( pArea ) != SUCCESS )
|
|
{
|
|
SELF_RELEASE( pArea );
|
|
return NULL;
|
|
}
|
|
|
|
return ( void * ) pArea;
|
|
}
|
|
|
|
HB_EXPORT ERRCODE hb_rddGetTempAlias( char * szAliasTmp )
|
|
{
|
|
int i, iArea;
|
|
|
|
for( i = 1; i < 1000; i++ )
|
|
{
|
|
snprintf( szAliasTmp, 11, "__HBTMP%03i", i);
|
|
if( hb_rddGetAliasNumber( szAliasTmp, &iArea ) != SUCCESS )
|
|
return SUCCESS;
|
|
}
|
|
szAliasTmp[0] = '\0';
|
|
return FAILURE;
|
|
}
|
|
|
|
/*
|
|
* allocate and return atomAlias for new workarea or NULL if alias already exist
|
|
*/
|
|
HB_EXPORT void * hb_rddAllocWorkAreaAlias( const char * szAlias, int iArea )
|
|
{
|
|
PHB_DYNS pSymAlias;
|
|
int iDummyArea;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddAllocWorkAreaAlias(%s, %d)", szAlias, iArea));
|
|
|
|
/* Verify if the alias name is valid symbol */
|
|
if( hb_rddVerifyAliasName( szAlias ) != SUCCESS )
|
|
{
|
|
hb_errRT_DBCMD_Ext( EG_BADALIAS, EDBCMD_BADALIAS, NULL, szAlias, EF_CANDEFAULT );
|
|
return NULL;
|
|
}
|
|
/* Verify if the alias is already in use */
|
|
if( hb_rddGetAliasNumber( szAlias, &iDummyArea ) == SUCCESS )
|
|
{
|
|
hb_errRT_DBCMD_Ext( EG_DUPALIAS, EDBCMD_DUPALIAS, NULL, szAlias, EF_CANDEFAULT );
|
|
return NULL;
|
|
}
|
|
|
|
pSymAlias = hb_dynsymGet( szAlias );
|
|
if( hb_dynsymAreaHandle( pSymAlias ) != 0 )
|
|
{
|
|
pSymAlias = NULL;
|
|
}
|
|
else
|
|
{
|
|
hb_dynsymSetAreaHandle( pSymAlias, iArea );
|
|
}
|
|
|
|
if( ! pSymAlias )
|
|
{
|
|
hb_errRT_DBCMD_Ext( EG_DUPALIAS, EDBCMD_DUPALIAS, NULL, szAlias, EF_CANDEFAULT );
|
|
}
|
|
|
|
return pSymAlias;
|
|
}
|
|
|
|
/*
|
|
* Find a field index by name
|
|
*/
|
|
HB_EXPORT USHORT hb_rddFieldIndex( AREAP pArea, const char * szName )
|
|
{
|
|
USHORT uiCount = 0;
|
|
LPFIELD pField;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddFieldIndex(%p, %s)", pArea, szName));
|
|
|
|
while( HB_ISSPACE( *szName ) )
|
|
{
|
|
++szName;
|
|
}
|
|
|
|
if( *szName )
|
|
{
|
|
char szSym[ HB_SYMBOL_NAME_LEN + 1 ];
|
|
hb_strncpyUpperTrim( szSym, szName, HB_SYMBOL_NAME_LEN );
|
|
|
|
pField = pArea->lpFields;
|
|
while( pField )
|
|
{
|
|
++uiCount;
|
|
if( strcmp( szSym, hb_dynsymName( ( PHB_DYNS ) pField->sym ) ) == 0 )
|
|
return uiCount;
|
|
pField = pField->lpfNext;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* find a field expression index, this function strips _FIELD->, FIELD->,
|
|
* alias-> prefixes
|
|
*/
|
|
HB_EXPORT USHORT hb_rddFieldExpIndex( AREAP pArea, const char * szField )
|
|
{
|
|
int n;
|
|
|
|
while( HB_ISSPACE( *szField ) )
|
|
{
|
|
++szField;
|
|
}
|
|
|
|
if( strchr( szField, '>' ) != NULL )
|
|
{
|
|
char szAlias[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ];
|
|
int i, j, l;
|
|
|
|
n = 0;
|
|
if( SELF_ALIAS( pArea, ( BYTE * ) szAlias ) == SUCCESS )
|
|
l = strlen( szAlias );
|
|
else
|
|
l = 0;
|
|
|
|
/*
|
|
* strip the _FIELD-> and FIELD-> prefix, it could be nested
|
|
* so repeat this process until all prefixes will be removed
|
|
*/
|
|
do
|
|
{
|
|
j = n;
|
|
i = 0;
|
|
if( HB_ISFIRSTIDCHAR( szField[ n ] ) )
|
|
{
|
|
++i;
|
|
while( HB_ISNEXTIDCHAR( szField[ n + i ] ) )
|
|
++i;
|
|
|
|
if( !( ( i == l &&
|
|
hb_strnicmp( &szField[ n ], szAlias, l ) == 0 ) ) &&
|
|
!( i >=4 && i <= 5 &&
|
|
hb_strnicmp( &szField[ n ], "FIELD", i ) == 0 ) &&
|
|
!( i >=4 && i <= 6 &&
|
|
hb_strnicmp( &szField[ n ], "_FIELD", i ) == 0 ) )
|
|
{
|
|
i = 0;
|
|
}
|
|
}
|
|
|
|
if( i > 0 )
|
|
{
|
|
i += n;
|
|
while( HB_ISSPACE( szField[ i ] ) )
|
|
i++;
|
|
if( szField[ i ] == '-' && szField[ i + 1 ] == '>' )
|
|
{
|
|
n = i + 2;
|
|
while( szField[ n ] == ' ' )
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
while( n != j );
|
|
szField = &szField[ n ];
|
|
}
|
|
return hb_rddFieldIndex( pArea, szField );
|
|
}
|
|
|
|
/*
|
|
* Find a WorkArea by the alias, return FAILURE if not found
|
|
*/
|
|
HB_EXPORT ERRCODE hb_rddGetAliasNumber( const char * szAlias, int * iArea )
|
|
{
|
|
BOOL fOneLetter;
|
|
char c;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddGetAliasNumber(%s, %p)", szAlias, iArea));
|
|
|
|
while( *szAlias == ' ' )
|
|
{
|
|
szAlias++;
|
|
}
|
|
c = szAlias[ 0 ];
|
|
if( c >= 'a' && c <= 'z' )
|
|
{
|
|
c -= 'a' - 'A';
|
|
}
|
|
|
|
fOneLetter = c && ( szAlias[ 1 ] == 0 || szAlias[ 1 ] == ' ' );
|
|
|
|
if( c >= '0' && c <= '9' )
|
|
{
|
|
*iArea = atoi( szAlias );
|
|
}
|
|
else if( fOneLetter && c >= 'A' && c <= 'K' )
|
|
{
|
|
*iArea = c - 'A' + 1;
|
|
}
|
|
else if( fOneLetter && c == 'M' )
|
|
{
|
|
*iArea = HARBOUR_MAX_RDD_AREA_NUM;
|
|
}
|
|
else
|
|
{
|
|
PHB_DYNS pSymAlias = hb_dynsymFindName( szAlias );
|
|
|
|
*iArea = pSymAlias ? ( int ) hb_dynsymAreaHandle( pSymAlias ) : 0;
|
|
if( *iArea == 0 )
|
|
{
|
|
return FAILURE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Select a WorkArea by the symbol name.
|
|
*/
|
|
HB_EXPORT ERRCODE hb_rddSelectWorkAreaSymbol( PHB_SYMB pSymAlias )
|
|
{
|
|
HB_ITEM_PTR pError;
|
|
ERRCODE errCode;
|
|
const char * szName;
|
|
int iArea;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddSelectWorkAreaSymbol(%p)", pSymAlias));
|
|
|
|
iArea = ( int ) hb_dynsymAreaHandle( pSymAlias->pDynSym );
|
|
if( iArea )
|
|
{
|
|
hb_rddSelectWorkAreaNumber( iArea );
|
|
return SUCCESS;
|
|
}
|
|
|
|
szName = hb_dynsymName( pSymAlias->pDynSym );
|
|
|
|
if( szName[ 0 ] && ! szName[ 1 ] )
|
|
{
|
|
if( szName[ 0 ] >= 'A' && szName[ 0 ] <= 'K' )
|
|
{
|
|
hb_rddSelectWorkAreaNumber( szName[ 0 ] - 'A' + 1 );
|
|
return SUCCESS;
|
|
}
|
|
else if( szName[ 0 ] >= 'a' && szName[ 0 ] <= 'k' )
|
|
{
|
|
hb_rddSelectWorkAreaNumber( szName[ 0 ] - 'a' + 1 );
|
|
return SUCCESS;
|
|
}
|
|
else if( szName[ 0 ] == 'M' || szName[ 0 ] == 'm' )
|
|
{
|
|
hb_rddSelectWorkAreaNumber( HARBOUR_MAX_RDD_AREA_NUM );
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* generate an error with retry possibility
|
|
* (user created error handler can open a missing database)
|
|
*/
|
|
|
|
pError = hb_errRT_New( ES_ERROR, NULL, EG_NOALIAS, EDBCMD_NOALIAS, NULL, pSymAlias->szName, 0, EF_CANRETRY );
|
|
errCode = FAILURE;
|
|
|
|
do
|
|
{
|
|
if( hb_errLaunch( pError ) != E_RETRY )
|
|
break;
|
|
iArea = ( int ) hb_dynsymAreaHandle( pSymAlias->pDynSym );
|
|
if( iArea )
|
|
{
|
|
hb_rddSelectWorkAreaNumber( iArea );
|
|
errCode = SUCCESS;
|
|
}
|
|
}
|
|
while( errCode == FAILURE );
|
|
|
|
hb_itemRelease( pError );
|
|
|
|
return errCode;
|
|
}
|
|
|
|
/*
|
|
* Select a WorkArea by the name.
|
|
*/
|
|
HB_EXPORT ERRCODE hb_rddSelectWorkAreaAlias( const char * szAlias )
|
|
{
|
|
ERRCODE errCode;
|
|
int iArea;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddSelectWorkAreaAlias(%s)", szAlias));
|
|
|
|
errCode = hb_rddGetAliasNumber( szAlias, &iArea );
|
|
|
|
if( errCode == FAILURE )
|
|
{
|
|
/*
|
|
* generate an error with retry possibility
|
|
* (user created error handler can open a missing database)
|
|
*/
|
|
HB_ITEM_PTR pError = hb_errRT_New( ES_ERROR, NULL, EG_NOALIAS, EDBCMD_NOALIAS, NULL, szAlias, 0, EF_CANRETRY );
|
|
|
|
do
|
|
{
|
|
if( hb_errLaunch( pError ) != E_RETRY )
|
|
break;
|
|
errCode = hb_rddGetAliasNumber( szAlias, &iArea );
|
|
}
|
|
while( errCode == FAILURE );
|
|
|
|
hb_itemRelease( pError );
|
|
}
|
|
|
|
if( errCode == SUCCESS )
|
|
{
|
|
if( iArea < 1 || iArea > HARBOUR_MAX_RDD_AREA_NUM )
|
|
errCode = hb_rddSelectFirstAvailable();
|
|
else
|
|
errCode = hb_rddSelectWorkAreaNumber( iArea );
|
|
}
|
|
|
|
return errCode;
|
|
}
|
|
|
|
/*
|
|
* Obtain the current value of a field.
|
|
*/
|
|
HB_EXPORT ERRCODE hb_rddFieldGet( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol )
|
|
{
|
|
AREAP pArea;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddFieldGet(%p, %p)", pItem, pFieldSymbol));
|
|
|
|
pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();
|
|
if( pArea )
|
|
{
|
|
USHORT uiField = 1;
|
|
LPFIELD pField = pArea->lpFields;
|
|
PHB_DYNS pDynSym = pFieldSymbol->pDynSym;
|
|
|
|
while( pField )
|
|
{
|
|
if( ( PHB_DYNS ) pField->sym == pDynSym )
|
|
{
|
|
return SELF_GETVALUE( pArea, uiField, pItem );
|
|
}
|
|
++uiField;
|
|
pField = pField->lpfNext;
|
|
}
|
|
}
|
|
return FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Assign a value to a field.
|
|
*/
|
|
HB_EXPORT ERRCODE hb_rddFieldPut( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol )
|
|
{
|
|
AREAP pArea;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddFieldPut(%p, %p)", pItem, pFieldSymbol));
|
|
|
|
pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();
|
|
if( pArea )
|
|
{
|
|
USHORT uiField = 1;
|
|
LPFIELD pField = pArea->lpFields;
|
|
PHB_DYNS pDynSym = pFieldSymbol->pDynSym;
|
|
|
|
while( pField )
|
|
{
|
|
if( ( PHB_DYNS ) pField->sym == pDynSym )
|
|
{
|
|
return SELF_PUTVALUE( pArea, uiField, pItem );
|
|
}
|
|
++uiField;
|
|
pField = pField->lpfNext;
|
|
}
|
|
}
|
|
return FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Obtain the current value of a field.
|
|
*/
|
|
HB_EXPORT ERRCODE hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol )
|
|
{
|
|
ERRCODE errCode;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddGetFieldValue(%p, %p)", pItem, pFieldSymbol));
|
|
|
|
errCode = hb_rddFieldGet( pItem, pFieldSymbol );
|
|
|
|
if( errCode == FAILURE && hb_vmRequestQuery() == 0 )
|
|
{
|
|
/*
|
|
* generate an error with retry possibility
|
|
* (user created error handler can make this field accessible)
|
|
*/
|
|
PHB_ITEM pError = hb_errRT_New( ES_ERROR, NULL, EG_NOVAR, EDBCMD_NOVAR,
|
|
NULL, pFieldSymbol->szName, 0, EF_CANRETRY );
|
|
|
|
while( hb_errLaunch( pError ) == E_RETRY )
|
|
{
|
|
errCode = hb_rddFieldGet( pItem, pFieldSymbol );
|
|
|
|
if( errCode == SUCCESS || hb_vmRequestQuery() != 0 )
|
|
break;
|
|
}
|
|
hb_itemRelease( pError );
|
|
}
|
|
|
|
return errCode;
|
|
}
|
|
|
|
/*
|
|
* Assign a value to a field.
|
|
*/
|
|
HB_EXPORT ERRCODE hb_rddPutFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol )
|
|
{
|
|
ERRCODE errCode;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_rddPutFieldValue(%p, %p)", pItem, pFieldSymbol));
|
|
|
|
errCode = hb_rddFieldPut( pItem, pFieldSymbol );
|
|
|
|
if( errCode == FAILURE && hb_vmRequestQuery() == 0 )
|
|
{
|
|
/*
|
|
* generate an error with retry possibility
|
|
* (user created error handler can make this field accessible)
|
|
*/
|
|
PHB_ITEM pError = hb_errRT_New( ES_ERROR, NULL, EG_NOVAR, EDBCMD_NOVAR,
|
|
NULL, pFieldSymbol->szName, 0, EF_CANRETRY );
|
|
|
|
while( hb_errLaunch( pError ) == E_RETRY )
|
|
{
|
|
errCode = hb_rddFieldPut( pItem, pFieldSymbol );
|
|
|
|
if( errCode == SUCCESS || hb_vmRequestQuery() != 0 )
|
|
break;
|
|
}
|
|
hb_itemRelease( pError );
|
|
}
|
|
|
|
return errCode;
|
|
}
|
|
|
|
ERRCODE hb_rddOpenTable( const char * szFileName, const char * szDriver,
|
|
USHORT uiArea, const char *szAlias,
|
|
BOOL fShared, BOOL fReadonly,
|
|
const char * szCpId, ULONG ulConnection,
|
|
PHB_ITEM pStruct, PHB_ITEM pDelim )
|
|
{
|
|
char szDriverBuffer[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ];
|
|
DBOPENINFO pInfo;
|
|
ERRCODE errCode;
|
|
AREAP pArea;
|
|
|
|
/* 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 );
|
|
|
|
/* 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 );
|
|
|
|
/* First try to create new are node and validate RDD name */
|
|
if( ! hb_rddInsertAreaNode( szDriver ) )
|
|
{
|
|
hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, HB_ERR_FUNCNAME );
|
|
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, HB_ERR_FUNCNAME );
|
|
return FAILURE;
|
|
}
|
|
|
|
pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();
|
|
|
|
/* Fill pInfo structure */
|
|
pInfo.uiArea = pArea->uiArea;
|
|
pInfo.abName = ( BYTE * ) szFileName;
|
|
pInfo.atomAlias = ( BYTE * ) szAlias;
|
|
pInfo.fShared = fShared;
|
|
pInfo.fReadonly = fReadonly;
|
|
pInfo.cdpId = ( BYTE * ) szCpId;
|
|
pInfo.ulConnection = ulConnection;
|
|
pInfo.lpdbHeader = NULL;
|
|
|
|
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 );
|
|
}
|
|
|
|
if( errCode != SUCCESS )
|
|
hb_rddReleaseCurrentArea();
|
|
|
|
return errCode;
|
|
}
|
|
|
|
ERRCODE hb_rddCreateTable( const char * szFileName, const char * szDriver,
|
|
USHORT uiArea, const char *szAlias,
|
|
BOOL fKeepOpen,
|
|
const char * szCpId, ULONG ulConnection,
|
|
PHB_ITEM pStruct, PHB_ITEM pDelim )
|
|
{
|
|
char szDriverBuffer[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ];
|
|
DBOPENINFO pInfo;
|
|
ERRCODE errCode;
|
|
USHORT uiPrevArea;
|
|
AREAP pArea;
|
|
|
|
if( !szFileName )
|
|
{
|
|
hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, HB_ERR_FUNCNAME );
|
|
return FAILURE;
|
|
}
|
|
|
|
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
|
|
* 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_rddSelectWorkAreaNumber( uiPrevArea );
|
|
hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, HB_ERR_FUNCNAME );
|
|
return FAILURE;
|
|
}
|
|
pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();
|
|
|
|
/* Fill pInfo structure */
|
|
pInfo.uiArea = pArea->uiArea;
|
|
pInfo.abName = ( BYTE * ) szFileName;
|
|
pInfo.atomAlias = ( BYTE * ) szAlias;
|
|
pInfo.fShared = FALSE;
|
|
pInfo.fReadonly = FALSE;
|
|
pInfo.cdpId = ( BYTE * ) szCpId;
|
|
pInfo.ulConnection = ulConnection;
|
|
pInfo.lpdbHeader = NULL;
|
|
|
|
if( pDelim && !HB_IS_NIL( pDelim ) )
|
|
errCode = SELF_INFO( pArea, DBI_SETDELIMITER, pDelim );
|
|
else
|
|
errCode = SUCCESS;
|
|
|
|
if( errCode == SUCCESS )
|
|
{
|
|
errCode = SELF_CREATEFIELDS( pArea, pStruct );
|
|
if( errCode == SUCCESS )
|
|
errCode = SELF_CREATE( pArea, &pInfo );
|
|
}
|
|
|
|
if( !fKeepOpen || errCode != SUCCESS )
|
|
{
|
|
hb_rddReleaseCurrentArea();
|
|
hb_rddSelectWorkAreaNumber( uiPrevArea );
|
|
}
|
|
|
|
return errCode;
|
|
}
|
|
|
|
static void hb_fldStructure( AREAP pArea, USHORT uiField, USHORT uiSize,
|
|
PHB_ITEM pField )
|
|
{
|
|
#define HB_DBS_ALEN ( sizeof( s_uiActions ) / sizeof( int ) )
|
|
#ifdef DBS_FLAG
|
|
static const int s_uiActions[] =
|
|
{ DBS_NAME, DBS_TYPE, DBS_LEN, DBS_DEC, DBS_FLAG };
|
|
#else
|
|
static const int s_uiActions[] =
|
|
{ DBS_NAME, DBS_TYPE, DBS_LEN, DBS_DEC };
|
|
#endif
|
|
USHORT uiCount;
|
|
|
|
if( uiSize == 0 || uiSize > HB_DBS_ALEN )
|
|
uiSize = HB_DBS_ALEN;
|
|
|
|
hb_arrayNew( pField, uiSize );
|
|
for( uiCount = 0; uiCount < uiSize; ++uiCount )
|
|
{
|
|
SELF_FIELDINFO( pArea, uiField, s_uiActions[uiCount],
|
|
hb_arrayGetItemPtr( pField, uiCount + 1 ) );
|
|
}
|
|
}
|
|
|
|
void hb_tblStructure( AREAP pArea, PHB_ITEM pStruct, USHORT uiSize )
|
|
{
|
|
USHORT uiFields, uiCount;
|
|
|
|
if( SELF_FIELDCOUNT( pArea, &uiFields ) == SUCCESS )
|
|
{
|
|
if( hb_arraySize( pStruct, uiFields ) )
|
|
{
|
|
for( uiCount = 1; uiCount <= uiFields; ++uiCount )
|
|
hb_fldStructure( pArea, uiCount, uiSize,
|
|
hb_arrayGetItemPtr( pStruct, uiCount ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
static char * hb_dbTransFieldPos( PHB_ITEM pFields, USHORT uiField )
|
|
{
|
|
char * szField = NULL;
|
|
PHB_ITEM pItem;
|
|
|
|
pItem = hb_arrayGetItemPtr( pFields, uiField );
|
|
if( pItem )
|
|
{
|
|
HB_TYPE type = hb_itemType( pItem );
|
|
|
|
if( type & HB_IT_ARRAY )
|
|
szField = hb_arrayGetCPtr( pItem, DBS_NAME );
|
|
else if( type & HB_IT_STRING )
|
|
szField = hb_itemGetCPtr( pItem );
|
|
|
|
if( * szField == '\0' )
|
|
szField = NULL;
|
|
}
|
|
|
|
return szField;
|
|
}
|
|
|
|
ERRCODE hb_dbTransStruct( AREAP lpaSource, AREAP lpaDest,
|
|
LPDBTRANSINFO lpdbTransInfo,
|
|
PHB_ITEM *pStruct, PHB_ITEM pFields )
|
|
{
|
|
USHORT uiFields, uiSize, uiCount, uiPosSrc, uiPosDst, uiSizeSrc, uiSizeDst;
|
|
ERRCODE errCode;
|
|
char * szField;
|
|
BOOL fAll;
|
|
|
|
errCode = SELF_FIELDCOUNT( lpaSource, &uiSizeSrc );
|
|
if( errCode != SUCCESS )
|
|
return errCode;
|
|
|
|
if( lpaDest )
|
|
{
|
|
errCode = SELF_FIELDCOUNT( lpaDest, &uiSizeDst );
|
|
if( errCode != SUCCESS )
|
|
return errCode;
|
|
uiSize = HB_MIN( uiSizeDst, uiSizeSrc );
|
|
}
|
|
else
|
|
{
|
|
uiSize = uiSizeDst = uiSizeSrc;
|
|
}
|
|
|
|
if( !uiSize )
|
|
return FAILURE;
|
|
if( hb_itemType( pFields ) & HB_IT_ARRAY )
|
|
{
|
|
uiFields = ( USHORT ) hb_arrayLen( pFields );
|
|
if( uiFields )
|
|
uiSize = uiFields;
|
|
}
|
|
else
|
|
uiFields = 0;
|
|
|
|
fAll = ( uiSizeDst == uiSizeSrc );
|
|
|
|
lpdbTransInfo->lpaSource = lpaSource;
|
|
lpdbTransInfo->lpaDest = lpaDest;
|
|
lpdbTransInfo->lpTransItems = ( LPDBTRANSITEM )
|
|
hb_xgrab( uiSize * sizeof( DBTRANSITEM ) );
|
|
|
|
if( !lpaDest )
|
|
{
|
|
*pStruct = hb_itemNew( NULL );
|
|
hb_arrayNew( *pStruct, 0 );
|
|
}
|
|
|
|
if( uiFields == 0 )
|
|
{
|
|
if( lpaDest )
|
|
{
|
|
PHB_ITEM pItem = hb_itemNew( NULL );
|
|
uiSize = 0;
|
|
for( uiCount = 1; uiCount <= uiSizeSrc; ++uiCount )
|
|
{
|
|
if( SELF_FIELDINFO( lpaSource, uiCount, DBS_NAME, pItem ) != SUCCESS )
|
|
{
|
|
uiSize = 0;
|
|
break;
|
|
}
|
|
szField = hb_itemGetCPtr( pItem );
|
|
uiPosDst = hb_rddFieldExpIndex( lpaDest, szField );
|
|
if( uiPosDst != uiCount )
|
|
fAll = FALSE;
|
|
if( uiPosDst )
|
|
{
|
|
USHORT ui;
|
|
|
|
/* check for replicated field names in source area */
|
|
for( ui = 0; ui < uiSize; ++ui )
|
|
{
|
|
if( lpdbTransInfo->lpTransItems[ ui ].uiDest == uiPosDst )
|
|
break;
|
|
}
|
|
if( ui == uiSize )
|
|
{
|
|
lpdbTransInfo->lpTransItems[ uiSize ].uiSource = uiCount;
|
|
lpdbTransInfo->lpTransItems[ uiSize++ ].uiDest = uiPosDst;
|
|
}
|
|
}
|
|
}
|
|
hb_itemRelease( pItem );
|
|
}
|
|
else
|
|
{
|
|
hb_tblStructure( lpaSource, *pStruct, 0 );
|
|
uiSize = ( USHORT ) hb_arrayLen( *pStruct );
|
|
for( uiCount = 0; uiCount < uiSize; ++uiCount )
|
|
{
|
|
lpdbTransInfo->lpTransItems[ uiCount ].uiSource =
|
|
lpdbTransInfo->lpTransItems[ uiCount ].uiDest = uiCount + 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiSize = 0;
|
|
for( uiCount = 1; uiCount <= uiFields; ++uiCount )
|
|
{
|
|
szField = hb_dbTransFieldPos( pFields, uiCount );
|
|
if( szField )
|
|
{
|
|
uiPosSrc = hb_rddFieldExpIndex( lpaSource, szField );
|
|
if( !uiPosSrc )
|
|
continue;
|
|
if( lpaDest )
|
|
uiPosDst = hb_rddFieldExpIndex( lpaDest, szField );
|
|
else
|
|
uiPosDst = uiSize + 1;
|
|
if( uiPosDst )
|
|
{
|
|
if( uiPosSrc != uiPosDst )
|
|
fAll = FALSE;
|
|
lpdbTransInfo->lpTransItems[ uiSize ].uiSource = uiPosSrc;
|
|
lpdbTransInfo->lpTransItems[ uiSize++ ].uiDest = uiPosDst;
|
|
if( !lpaDest )
|
|
{
|
|
hb_arraySize( *pStruct, uiSize );
|
|
hb_fldStructure( lpaSource, uiPosSrc, 0,
|
|
hb_arrayGetItemPtr( *pStruct, uiSize ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( uiSize != uiSizeSrc )
|
|
fAll = FALSE;
|
|
|
|
if( fAll && lpaDest )
|
|
{
|
|
PHB_ITEM pSrcItm = hb_itemNew( NULL ),
|
|
pDstItm = hb_itemNew( NULL );
|
|
/*
|
|
* if fAll is TRUE here then it means that all fields are included
|
|
* and they are on the same positions in both tables, so now check
|
|
* if their types and sizes are also equal
|
|
*/
|
|
for( uiCount = 1; uiCount <= uiSize; ++uiCount )
|
|
{
|
|
if( SELF_FIELDINFO( lpaSource, uiCount, DBS_TYPE, pSrcItm ) != SUCCESS ||
|
|
SELF_FIELDINFO( lpaDest, uiCount, DBS_TYPE, pDstItm ) != SUCCESS )
|
|
{
|
|
uiSize = 0;
|
|
break;
|
|
}
|
|
if( hb_stricmp( hb_itemGetCPtr( pSrcItm ),
|
|
hb_itemGetCPtr( pDstItm ) ) != 0 )
|
|
{
|
|
fAll = FALSE;
|
|
break;
|
|
}
|
|
if( SELF_FIELDINFO( lpaSource, uiCount, DBS_LEN, pSrcItm ) != SUCCESS ||
|
|
SELF_FIELDINFO( lpaDest, uiCount, DBS_LEN, pDstItm ) != SUCCESS )
|
|
{
|
|
uiSize = 0;
|
|
break;
|
|
}
|
|
if( hb_itemGetNL( pSrcItm ) != hb_itemGetNL( pDstItm ) )
|
|
{
|
|
fAll = FALSE;
|
|
break;
|
|
}
|
|
if( SELF_FIELDINFO( lpaSource, uiCount, DBS_DEC, pSrcItm ) != SUCCESS ||
|
|
SELF_FIELDINFO( lpaDest, uiCount, DBS_DEC, pDstItm ) != SUCCESS )
|
|
{
|
|
uiSize = 0;
|
|
break;
|
|
}
|
|
if( hb_itemGetNL( pSrcItm ) != hb_itemGetNL( pDstItm ) )
|
|
{
|
|
fAll = FALSE;
|
|
break;
|
|
}
|
|
#ifdef DBS_FLAG
|
|
if( SELF_FIELDINFO( lpaSource, uiCount, DBS_FLAG, pSrcItm ) != SUCCESS ||
|
|
SELF_FIELDINFO( lpaDest, uiCount, DBS_FLAG, pDstItm ) != SUCCESS )
|
|
{
|
|
uiSize = 0;
|
|
break;
|
|
}
|
|
#endif
|
|
if( hb_itemGetNL( pSrcItm ) != hb_itemGetNL( pDstItm ) )
|
|
{
|
|
fAll = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
hb_itemRelease( pSrcItm );
|
|
hb_itemRelease( pDstItm );
|
|
}
|
|
|
|
lpdbTransInfo->uiFlags = fAll ? DBTF_MATCH : 0;
|
|
lpdbTransInfo->uiItemCount = uiSize;
|
|
|
|
return uiSize ? SUCCESS : FAILURE;
|
|
}
|
|
|
|
ERRCODE hb_rddTransRecords( AREAP pArea,
|
|
const char *szFileName, const char *szDriver,
|
|
ULONG ulConnection,
|
|
PHB_ITEM pFields, BOOL fExport,
|
|
PHB_ITEM pCobFor, PHB_ITEM pStrFor,
|
|
PHB_ITEM pCobWhile, PHB_ITEM pStrWhile,
|
|
PHB_ITEM pNext, PHB_ITEM pRecID,
|
|
PHB_ITEM pRest,
|
|
const char *szCpId,
|
|
PHB_ITEM pDelim )
|
|
{
|
|
AREAP lpaClose = NULL;
|
|
PHB_ITEM pStruct = NULL;
|
|
DBTRANSINFO dbTransInfo;
|
|
USHORT uiPrevArea, uiCount, uiSwap;
|
|
ERRCODE errCode;
|
|
|
|
memset( &dbTransInfo, 0, sizeof( DBTRANSINFO ) );
|
|
uiPrevArea = hb_rddGetCurrentWorkAreaNumber();
|
|
|
|
if( szDriver == NULL )
|
|
/* szDriver = SELF_RDDNODE( pArea )->szName; */
|
|
szDriver = hb_rddDefaultDrv( NULL );
|
|
|
|
if( fExport )
|
|
{
|
|
errCode = hb_dbTransStruct( pArea, NULL, &dbTransInfo,
|
|
&pStruct, pFields );
|
|
if( errCode == SUCCESS )
|
|
{
|
|
errCode = hb_rddCreateTable( szFileName, szDriver, 0, "",
|
|
TRUE,
|
|
szCpId, ulConnection, pStruct, pDelim );
|
|
if( errCode == SUCCESS )
|
|
{
|
|
dbTransInfo.lpaDest = lpaClose =
|
|
( AREAP ) hb_rddGetCurrentWorkAreaPointer();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPRDDNODE pRddNode = hb_rddFindNode( szDriver, NULL );
|
|
|
|
if( !pRddNode )
|
|
{
|
|
hb_errRT_DBCMD( EG_ARG, EDBCMD_USE_BADPARAMETER, NULL, HB_ERR_FUNCNAME );
|
|
return FAILURE;
|
|
}
|
|
|
|
if( pRddNode->uiType == RDT_TRANSFER )
|
|
{
|
|
errCode = hb_dbTransStruct( pArea, NULL, &dbTransInfo,
|
|
&pStruct, pFields );
|
|
|
|
/* revert area and items */
|
|
dbTransInfo.lpaDest = dbTransInfo.lpaSource;
|
|
for( uiCount = 0; uiCount < dbTransInfo.uiItemCount; ++uiCount )
|
|
{
|
|
uiSwap = dbTransInfo.lpTransItems[uiCount].uiSource;
|
|
dbTransInfo.lpTransItems[uiCount].uiSource =
|
|
dbTransInfo.lpTransItems[uiCount].uiDest;
|
|
dbTransInfo.lpTransItems[uiCount].uiDest = uiSwap;
|
|
}
|
|
|
|
if( errCode == SUCCESS )
|
|
{
|
|
errCode = hb_rddOpenTable( szFileName, szDriver, 0, "", TRUE, TRUE,
|
|
szCpId, ulConnection, pStruct, pDelim );
|
|
if( errCode == SUCCESS )
|
|
{
|
|
lpaClose = dbTransInfo.lpaSource =
|
|
( AREAP ) hb_rddGetCurrentWorkAreaPointer();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errCode = hb_rddOpenTable( szFileName, szDriver, 0, "", TRUE, TRUE,
|
|
szCpId, ulConnection, NULL, pDelim );
|
|
if( errCode == SUCCESS )
|
|
{
|
|
lpaClose = ( AREAP ) hb_rddGetCurrentWorkAreaPointer();
|
|
errCode = hb_dbTransStruct( lpaClose, pArea, &dbTransInfo,
|
|
NULL, pFields );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pStruct )
|
|
hb_itemRelease( pStruct );
|
|
|
|
if( errCode == SUCCESS )
|
|
{
|
|
hb_rddSelectWorkAreaNumber( dbTransInfo.lpaSource->uiArea );
|
|
|
|
dbTransInfo.dbsci.itmCobFor = pCobFor;
|
|
dbTransInfo.dbsci.lpstrFor = pStrFor;
|
|
dbTransInfo.dbsci.itmCobWhile = pCobWhile;
|
|
dbTransInfo.dbsci.lpstrWhile = pStrWhile;
|
|
dbTransInfo.dbsci.lNext = pNext;
|
|
dbTransInfo.dbsci.itmRecID = pRecID;
|
|
dbTransInfo.dbsci.fRest = pRest;
|
|
|
|
dbTransInfo.dbsci.fIgnoreFilter = TRUE;
|
|
dbTransInfo.dbsci.fIncludeDeleted = TRUE;
|
|
dbTransInfo.dbsci.fLast = FALSE;
|
|
dbTransInfo.dbsci.fIgnoreDuplicates = FALSE;
|
|
dbTransInfo.dbsci.fBackward = FALSE;
|
|
|
|
errCode = SELF_TRANS( dbTransInfo.lpaSource, &dbTransInfo );
|
|
}
|
|
|
|
if( dbTransInfo.lpTransItems )
|
|
hb_xfree( dbTransInfo.lpTransItems );
|
|
if( lpaClose )
|
|
{
|
|
hb_rddSelectWorkAreaNumber( lpaClose->uiArea );
|
|
hb_rddReleaseCurrentArea();
|
|
}
|
|
hb_rddSelectWorkAreaNumber( uiPrevArea );
|
|
|
|
return errCode;
|
|
}
|