Files
harbour-core/contrib/rddsql/sqlmix.c
Viktor Szakats 5a2a287752 2017-09-08 16:00 UTC Viktor Szakats (vszakats users.noreply.github.com)
* *
    * partial sync with the 3.4 fork codebase. These are the things
      synces for the most part:
      - copyright headers
      - grammar/typos in comments and some readmes
      - comment/whitespace/decorations
      - variable scoping in C files
      - DO CASE/SWITCH and some other alternate syntax usage
      - minimal amount of human readable text in strings
      - minor code updates
      - HB_TRACE() void * casts for pointers and few other changes to
        avoid C compiler warnings
      - various other, minor code cleanups
      - only Harbour/C code/headers were touched in src, utils, contrib,
        include. No 3rd party code, no make files, and with just a few
        exceptions, no 'tests' code was touched.
      - certain components were not touched were 3.4 diverged too much
        already, like f.e. hbmk2, hbssl, hbcurl, hbexpat
      - the goal was that no actual program logic should be altered by
        these changes. Except some possible minor exceptions, any such
        change is probably a bug in this patch.
      It's a massive patch, if you find anything broken after it, please
      open an Issue with the details. Build test was done on macOS.
      The goal is make it easier to see what actual code/logic was changed
      in 3.4 compared to 3.2 and to make patches easier to apply in both
      ways.
2017-09-08 16:25:13 +00:00

2124 lines
62 KiB
C

/*
* SQL MIX (Memory Index) Database Driver
*
* Copyright 2007 Mindaugas Kavaliauskas <dbtopas at dbtopas.lt>
*
* 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 program; see the file LICENSE.txt. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
*
* 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 "hbinit.h"
#include "hbapiitm.h"
#include "hbapirdd.h"
#include "hbapierr.h"
#include "hbdbferr.h"
#include "hbapilng.h"
#include "hbdate.h"
#include "hbset.h"
#include "hbvm.h"
#include "rddsys.ch"
#include "hbrddsql.h"
#define SUPERTABLE ( &sqlmixSuper )
#define MIX_KEY( tag, node, index ) \
( ( PMIXKEY ) &( ( HB_BYTE * ) ( node ) )[ ( ( node )->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + ( index ) * ( tag )->uiTotalLen ] )
#define MIX_COPY_KEYS_INTERNAL( tag, node, dst, src, count ) \
memmove( ( ( HB_BYTE * ) ( node ) ) + ( ( node )->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + ( dst ) * ( tag )->uiTotalLen, \
( ( HB_BYTE * ) ( node ) ) + ( ( node )->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + ( src ) * ( tag )->uiTotalLen, \
( count ) * ( tag )->uiTotalLen )
#define MIX_COPY_KEYS_EXTERNAL( tag, ndst, dst, nsrc, src, count ) \
memmove( ( ( HB_BYTE * ) ( ndst ) ) + ( ( ndst )->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + ( dst ) * ( tag )->uiTotalLen, \
( ( HB_BYTE * ) ( nsrc ) ) + ( ( nsrc )->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + ( src ) * ( tag )->uiTotalLen, \
( count ) * ( tag )->uiTotalLen )
#define MIX_ASSIGN_KEY( tag, node, dst, src ) \
memmove( ( ( HB_BYTE * ) ( node ) ) + ( ( node )->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + ( dst ) * ( tag )->uiTotalLen, \
( src ), ( tag )->uiTotalLen )
#define MIX_COPY_CHILDS_INTERNAL( tag, node, dst, src, count ) \
memmove( &( ( node )->Child[ ( dst ) ] ), &( ( node )->Child[ ( src ) ] ), ( count ) * sizeof( void * ) )
#define MIX_COPY_CHILDS_EXTERNAL( tag, ndst, dst, nsrc, src, count ) \
memmove( &( ( ndst )->Child[ ( dst ) ] ), &( ( nsrc )->Child[ ( src ) ] ), ( count ) * sizeof( void * ) )
static HB_USHORT s_uiRddIdSQLMIX = ( HB_USHORT ) -1;
static RDDFUNCS sqlmixSuper;
/* --- Misc functions --- */
static HB_ERRCODE sqlmixErrorRT( SQLMIXAREAP pArea, HB_ERRCODE errGenCode, HB_ERRCODE errSubCode, char * filename, HB_ERRCODE errOsCode, HB_USHORT uiFlags )
{
HB_ERRCODE iRet = HB_FAILURE;
if( hb_vmRequestQuery() == 0 )
{
PHB_ITEM pError = hb_errNew();
hb_errPutGenCode( pError, errGenCode );
hb_errPutSubCode( pError, errSubCode );
hb_errPutOsCode( pError, errOsCode );
hb_errPutDescription( pError, hb_langDGetErrorDesc( errGenCode ) );
if( filename )
hb_errPutFileName( pError, filename );
if( uiFlags )
hb_errPutFlags( pError, uiFlags );
iRet = SELF_ERROR( &pArea->sqlarea.area, pError );
hb_errRelease( pError );
}
return iRet;
}
/* --- Memory Index --- */
/* --- Key management --- */
/* hb_mixKey*() */
static PMIXKEY hb_mixKeyNew( PMIXTAG pTag )
{
return ( PMIXKEY ) hb_xgrab( pTag->uiTotalLen );
}
static PMIXKEY hb_mixKeyPutItem( PMIXKEY pKey, PHB_ITEM pItem, HB_ULONG ulRecNo, PMIXTAG pTag )
{
double dbl;
HB_BYTE buf[ 8 ];
if( ! pKey )
pKey = hb_mixKeyNew( pTag );
pKey->rec = ulRecNo;
pKey->notnul = 1;
/* TODO: check valtype */
switch( pTag->bType )
{
case 'C':
{
HB_SIZE nLen = hb_itemGetCLen( pItem );
if( nLen > ( HB_SIZE ) pTag->uiKeyLen )
nLen = pTag->uiKeyLen;
memcpy( pKey->val, hb_itemGetCPtr( pItem ), nLen );
if( nLen < ( HB_SIZE ) pTag->uiKeyLen )
memset( pKey->val + nLen, ' ', ( HB_SIZE ) pTag->uiKeyLen - nLen );
break;
}
case 'N':
dbl = hb_itemGetND( pItem );
HB_DBL2ORD( &dbl, buf );
memcpy( pKey->val, buf, 8 );
break;
case 'D':
dbl = ( double ) hb_itemGetDL( pItem );
HB_DBL2ORD( &dbl, buf );
memcpy( pKey->val, buf, 8 );
break;
case 'L':
pKey->val[ 0 ] = ( HB_BYTE ) ( hb_itemGetL( pItem ) ? 'T' : 'F' );
break;
default:
pKey->notnul = 0;
memset( pKey->val, ' ', pTag->uiKeyLen );
}
return pKey;
}
static PMIXKEY hb_mixKeyEval( PMIXKEY pKey, PMIXTAG pTag )
{
PHB_ITEM pItem;
SQLMIXAREAP pArea = pTag->pArea;
int iCurrArea = hb_rddGetCurrentWorkAreaNumber();
PHB_CODEPAGE pCodepage = hb_cdpSelect( pArea->sqlarea.area.cdPage );
if( iCurrArea != pArea->sqlarea.area.uiArea )
hb_rddSelectWorkAreaNumber( pArea->sqlarea.area.uiArea );
else
iCurrArea = 0;
pItem = hb_vmEvalBlockOrMacro( pTag->pKeyItem );
pKey = hb_mixKeyPutItem( pKey, pItem, pArea->sqlarea.ulRecNo, pTag );
if( iCurrArea )
hb_rddSelectWorkAreaNumber( iCurrArea );
hb_cdpSelect( pCodepage );
return pKey;
}
static HB_BOOL hb_mixEvalCond( SQLMIXAREAP pArea, PHB_ITEM pCondItem )
{
int iCurrArea = 0;
HB_BOOL fRet;
if( pArea )
{
iCurrArea = hb_rddGetCurrentWorkAreaNumber();
if( iCurrArea != pArea->sqlarea.area.uiArea )
hb_rddSelectWorkAreaNumber( pArea->sqlarea.area.uiArea );
else
iCurrArea = 0;
}
fRet = hb_itemGetL( hb_vmEvalBlockOrMacro( pCondItem ) );
if( iCurrArea )
hb_rddSelectWorkAreaNumber( iCurrArea );
return fRet;
}
static void hb_mixKeyFree( PMIXKEY pKey )
{
hb_xfree( pKey );
}
static int hb_mixKeyCompare( PMIXTAG pTag, PMIXKEY pKey1, PMIXKEY pKey2, unsigned int uiLen )
{
unsigned int uiSize;
int i;
if( ! pKey1->notnul || ! pKey2->notnul )
return ( int ) pKey1->notnul - ( int ) pKey2->notnul;
i = 0;
uiSize = pTag->uiKeyLen > uiLen ? uiLen : pTag->uiKeyLen;
if( pTag->pCodepage )
i = hb_cdpcmp( ( const char * ) pKey1->val, ( HB_SIZE ) uiSize, ( const char * ) pKey2->val, ( HB_SIZE ) uiSize, pTag->pCodepage, 0 );
else if( uiSize > 0 )
i = memcmp( pKey1->val, pKey2->val, uiSize );
if( i == 0 )
{
if( pKey2->rec == ( HB_ULONG ) -1 )
{
/* This condition seems inverted, but it's ok for seek last */
if( pTag->uiKeyLen > uiLen )
i = -1;
}
else
{
if( pTag->uiKeyLen > uiLen )
i = 1;
else if( pTag->uiKeyLen < uiLen )
i = -1;
}
}
if( i != 0 )
{
if( i < 0 )
return -2;
return 2;
}
if( pKey1->rec < pKey2->rec )
return -1;
else if( pKey1->rec > pKey2->rec )
return 1;
return 0;
}
/* --- Tag management --- */
/* hb_mixTag*() */
/* This function is used for debugging purposes. Uncomment it, if you need it. */
#if 0
static void hb_mixTagPrintNode( PMIXTAG pTag, PMIXNODE pNode, int iLevel )
{
unsigned int i;
if( ! pNode )
return;
if( pNode->KeyCount < MIX_NODE_ORDER / 2 && pNode->Parent )
printf( "!!! Too few keys\n" );
for( i = 0; i < pNode->KeyCount; i++ )
{
if( ! pNode->Leaf )
{
if( pNode->Child[ i ]->Parent != pNode )
printf( "!!! Invalid parent\n" );
hb_mixTagPrintNode( pTag, pNode->Child[ i ], iLevel + 1 );
}
printf( "%*ld %*s\n", iLevel * 10 + 5, MIX_KEY( pTag, pNode, i )->rec, pTag->uiKeyLen,
MIX_KEY( pTag, pNode, i )->notnul ? ( char * ) MIX_KEY( pTag, pNode, i )->val : "NULL" );
}
if( ! pNode->Leaf )
{
if( pNode->Child[ pNode->KeyCount ]->Parent != pNode )
printf( "!!! Invalid parent\n" );
hb_mixTagPrintNode( pTag, pNode->Child[ pNode->KeyCount ], iLevel + 1 );
}
}
#endif
static PMIXNODE hb_mixTagCreateNode( PMIXTAG pTag, HB_BOOL fLeaf )
{
HB_SIZE nSize = ( fLeaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + MIX_NODE_ORDER * pTag->uiTotalLen;
PMIXNODE pNode = ( PMIXNODE ) hb_xgrabz( nSize );
pNode->Leaf = fLeaf ? 1 : 0;
return pNode;
}
static unsigned int hb_mixTagNodeParentIndex( PMIXNODE pNode )
{
PMIXNODE pParent = pNode->Parent;
unsigned int ui;
/* Find position in the parent node */
ui = pParent->KeyCount;
do
{
if( pParent->Child[ ui ] == pNode )
return ui;
}
while( ui-- );
return ( unsigned int ) -1;
}
static int hb_mixTagFindKey( PMIXTAG pTag, PMIXKEY pKey, unsigned int uiLen, PMIXNODE * ppNode, unsigned int * puiPos, HB_BOOL fValidKey )
{
PMIXNODE pNode;
unsigned int ui;
int i;
pNode = pTag->Root;
for( ;; )
{
i = -2;
/* TODO: binary search */
for( ui = 0; ui < pNode->KeyCount; ui++ )
{
i = hb_mixKeyCompare( pTag, MIX_KEY( pTag, pNode, ui ), pKey, uiLen );
if( i >= 0 )
break;
}
if( i == 0 || pNode->Leaf )
break;
else
pNode = pNode->Child[ ui ];
}
if( fValidKey && ui >= pNode->KeyCount )
{
/* unsuccessful find always finds position in leaf */
while( pNode->Parent && pNode->Parent->Child[ pNode->Parent->KeyCount ] == pNode )
pNode = pNode->Parent;
if( pNode->Parent )
{
for( ui = 0; ui < pNode->Parent->KeyCount; ui++ )
{
if( pNode->Parent->Child[ ui ] == pNode )
{
pNode = pNode->Parent;
break;
}
}
}
else
ui = pNode->KeyCount + 1; /* EOF */
}
*ppNode = pNode;
*puiPos = ui;
return i;
}
static void hb_mixTagSetCurrent( PMIXTAG pTag, PMIXNODE pNode, unsigned int uiPos )
{
if( uiPos < pNode->KeyCount )
{
pTag->CurNode = pNode;
pTag->CurPos = uiPos;
pTag->CurKey = MIX_KEY( pTag, pNode, uiPos );
pTag->fEof = HB_FALSE;
}
else
pTag->fEof = HB_TRUE;
}
static HB_BOOL hb_mixTagRefreshKey( PMIXTAG pTag )
{
SQLMIXAREAP pArea;
pArea = pTag->pArea;
if( pArea->sqlarea.lpdbPendingRel )
SELF_FORCEREL( &pArea->sqlarea.area );
if( ! pArea->sqlarea.fPositioned )
{
pTag->fEof = HB_TRUE;
return HB_FALSE;
}
else if( pTag->fEof || pTag->CurKey->rec != pArea->sqlarea.ulRecNo )
{
PMIXKEY pKey;
PMIXNODE pNode;
unsigned int ui;
pKey = hb_mixKeyEval( NULL, pTag );
hb_mixTagFindKey( pTag, pKey, pTag->uiKeyLen, &pNode, &ui, HB_FALSE );
hb_mixTagSetCurrent( pTag, pNode, ui );
hb_mixKeyFree( pKey );
return ! pTag->fEof && pTag->CurKey->rec == pArea->sqlarea.ulRecNo;
}
pTag->fBof = pTag->fEof = HB_FALSE;
return HB_TRUE;
}
static void hb_mixTagAddKeyNode( PMIXTAG pTag, PMIXNODE pNode, unsigned int uiPos, PMIXKEY pKey, PMIXNODE pChildLeft, PMIXNODE pChildRight )
{
MIX_COPY_KEYS_INTERNAL( pTag, pNode, uiPos + 1, uiPos, pNode->KeyCount - uiPos );
if( ! pNode->Leaf )
{
MIX_COPY_CHILDS_INTERNAL( pTag, pNode, uiPos + 2, uiPos + 1, pNode->KeyCount - uiPos );
pNode->Child[ uiPos ] = pChildLeft;
pNode->Child[ uiPos + 1 ] = pChildRight;
pChildLeft->Parent = pNode;
pChildRight->Parent = pNode;
}
MIX_ASSIGN_KEY( pTag, pNode, uiPos, pKey );
pNode->KeyCount++;
}
static void hb_mixTagAddKeyPos( PMIXTAG pTag, PMIXNODE pNode, unsigned int uiPos, PMIXKEY pKey, PMIXNODE pChildLeft, PMIXNODE pChildRight )
{
PMIXNODE pNewNode;
unsigned int j, k;
if( pNode->KeyCount < MIX_NODE_ORDER )
{
hb_mixTagAddKeyNode( pTag, pNode, uiPos, pKey, pChildLeft, pChildRight );
return;
}
#ifdef USE_SIBLINGS
/* Try use siblings, if leaf node is full */
if( pNode->Leaf && pNode->Parent )
{
j = hb_mixTagNodeParentIndex( pNode );
if( j > 0 && pNode->Parent->Child[ j - 1 ]->KeyCount < MIX_NODE_ORDER )
{
MIX_COPY_KEYS_EXTERNAL( pTag, pNode->Parent->Child[ j - 1 ], pNode->Parent->Child[ j - 1 ]->KeyCount, pNode->Parent, j - 1, 1 );
pNode->Parent->Child[ j - 1 ]->KeyCount++;
if( uiPos == 0 )
{
MIX_ASSIGN_KEY( pTag, pNode->Parent, j - 1, pKey );
pNode->Parent->Key[ j - 1 ] = pKey;
}
else
{
MIX_COPY_KEYS_EXTERNAL( pTag, pNode->Parent, j - 1, pNode, 0, 1 );
uiPos--;
MIX_COPY_KEYS_INTERNAL( pTag, pNode, 0, 1, uiPos );
MIX_ASSIGN_KEY( pTag, pNode, uiPos, pKey );
}
return;
}
else if( j < pNode->Parent->KeyCount && pNode->Parent->Child[ j + 1 ]->KeyCount < MIX_NODE_ORDER )
{
MIX_COPY_KEYS_INTERNAL( pTag, pNode->Parent->Child[ j + 1 ], 1, 0, pNode->Parent->Child[ j + 1 ]->KeyCount );
MIX_COPY_KEYS_EXTERNAL( pTag, pNode->Parent->Child[ j + 1 ], 0, pNode->Parent, j, 1 );
pNode->Parent->Child[ j + 1 ]->KeyCount++;
if( uiPos == MIX_NODE_ORDER )
MIX_ASSIGN_KEY( pTag, pNode->Parent, j, pKey );
else
{
MIX_COPY_KEYS_EXTERNAL( pTag, pNode->Parent, j, pNode, MIX_NODE_ORDER - 1, 1 );
MIX_COPY_KEYS_INTERNAL( pTag, pNode, uiPos + 1, uiPos, MIX_NODE_ORDER - uiPos - 1 );
MIX_ASSIGN_KEY( pTag, pNode, uiPos, pKey );
}
return;
}
}
#endif /* USE_SIBLINGS */
/* Create new node */
pNewNode = hb_mixTagCreateNode( pTag, pNode->Leaf );
/* Move half of items to new node */
k = MIX_NODE_ORDER / 2 + ( ( uiPos <= MIX_NODE_ORDER / 2 ) ? 0 : 1 );
MIX_COPY_KEYS_EXTERNAL( pTag, pNewNode, 0, pNode, k, MIX_NODE_ORDER - k );
if( ! pNode->Leaf )
{
MIX_COPY_CHILDS_EXTERNAL( pTag, pNewNode, 1, pNode, k + 1, MIX_NODE_ORDER - k );
for( j = 1; j <= MIX_NODE_ORDER - k; j++ )
pNewNode->Child[ j ]->Parent = pNewNode; /* Do NOT forget to re-parent */
}
pNode->KeyCount = k;
pNewNode->KeyCount = MIX_NODE_ORDER - k;
/* Insert new item to the left node or right node */
if( uiPos <= MIX_NODE_ORDER / 2 )
hb_mixTagAddKeyNode( pTag, pNode, uiPos, pKey, pChildLeft, pChildRight );
else
hb_mixTagAddKeyNode( pTag, pNewNode, uiPos - MIX_NODE_ORDER / 2 - 1, pKey, pChildLeft, pChildRight );
/* Assign the leftmost child of the new node */
if( ! pNode->Leaf )
{
pNewNode->Child[ 0 ] = pNode->Child[ pNode->KeyCount ];
pNewNode->Child[ 0 ]->Parent = pNewNode;
}
pNode->KeyCount--;
/* Move middle (last+1 in first node) item up */
if( pNode->Parent )
hb_mixTagAddKeyPos( pTag, pNode->Parent, hb_mixTagNodeParentIndex( pNode ),
MIX_KEY( pTag, pNode, pNode->KeyCount ), pNode, pNewNode );
else
{
pTag->Root = hb_mixTagCreateNode( pTag, 0 );
hb_mixTagAddKeyNode( pTag, pTag->Root, 0, MIX_KEY( pTag, pNode, pNode->KeyCount ), pNode, pNewNode );
}
}
static HB_BOOL hb_mixTagAddKey( PMIXTAG pTag, PMIXKEY pKey )
{
PMIXNODE pNode;
unsigned int ui;
int i;
i = hb_mixTagFindKey( pTag, pKey, pTag->uiKeyLen, &pNode, &ui, HB_FALSE );
/* Key can not be duplicated */
if( ! i )
return HB_FALSE;
hb_mixTagAddKeyPos( pTag, pNode, ui, pKey, NULL, NULL );
return HB_TRUE;
}
static void hb_mixTagDelKeyNode( PMIXTAG pTag, PMIXNODE pNode, unsigned int uiPos )
{
MIX_COPY_KEYS_INTERNAL( pTag, pNode, uiPos, uiPos + 1, pNode->KeyCount - uiPos - 1 );
if( ! pNode->Leaf )
{
MIX_COPY_CHILDS_INTERNAL( pTag, pNode, uiPos, uiPos + 1, pNode->KeyCount - uiPos );
}
pNode->KeyCount--;
}
static void hb_mixTagNodeAdjust( PMIXTAG pTag, PMIXNODE pNode )
{
unsigned int i, j;
PMIXNODE pParent, pSibling;
for( ;; )
{
if( pNode->KeyCount >= MIX_NODE_ORDER / 2 )
return;
/* Check siblings */
if( pNode->Parent )
{
pParent = pNode->Parent;
j = hb_mixTagNodeParentIndex( pNode );
if( j > 0 && pParent->Child[ j - 1 ]->KeyCount > MIX_NODE_ORDER / 2 )
{
/* Borrow from left */
pSibling = pParent->Child[ j - 1 ];
/* It could not be pNode->Child[ 0 ] if it is not Leaf!!! */
hb_mixTagAddKeyNode( pTag, pNode, 0, MIX_KEY( pTag, pParent, j - 1 ), pSibling->Child[ pSibling->KeyCount ], pNode->Child[ 0 ] );
MIX_COPY_KEYS_EXTERNAL( pTag, pParent, j - 1, pSibling, pSibling->KeyCount - 1, 1 );
pSibling->KeyCount--;
return;
}
else if( j < pParent->KeyCount && pParent->Child[ j + 1 ]->KeyCount > MIX_NODE_ORDER / 2 )
{
/* Borrow from right */
pSibling = pParent->Child[ j + 1 ];
hb_mixTagAddKeyNode( pTag, pNode, pNode->KeyCount, MIX_KEY( pTag, pParent, j ), pNode->Child[ pNode->KeyCount ], pSibling->Child[ 0 ] );
MIX_COPY_KEYS_EXTERNAL( pTag, pParent, j, pSibling, 0, 1 );
hb_mixTagDelKeyNode( pTag, pSibling, 0 );
return;
}
else if( j > 0 )
{
/* Join with left */
pSibling = pParent->Child[ j - 1 ];
MIX_COPY_KEYS_EXTERNAL( pTag, pSibling, pSibling->KeyCount, pParent, j - 1, 1 );
pSibling->KeyCount++;
MIX_COPY_KEYS_EXTERNAL( pTag, pSibling, pSibling->KeyCount, pNode, 0, pNode->KeyCount );
if( pNode->Leaf )
pSibling->KeyCount += pNode->KeyCount;
else
{
MIX_COPY_CHILDS_EXTERNAL( pTag, pSibling, pSibling->KeyCount, pNode, 0, pNode->KeyCount );
for( i = 0; i < pNode->KeyCount; i++ )
pSibling->Child[ pSibling->KeyCount++ ]->Parent = pSibling;
pSibling->Child[ pSibling->KeyCount ] = pNode->Child[ i ];
pSibling->Child[ pSibling->KeyCount ]->Parent = pSibling;
}
hb_xfree( pNode );
pParent->Child[ j ] = pSibling;
hb_mixTagDelKeyNode( pTag, pParent, j - 1 );
pNode = pParent;
}
else if( j < pParent->KeyCount )
{
/* Join with right */
pSibling = pParent->Child[ j + 1 ];
MIX_COPY_KEYS_EXTERNAL( pTag, pNode, pNode->KeyCount, pParent, j, 1 );
pNode->KeyCount++;
MIX_COPY_KEYS_EXTERNAL( pTag, pNode, pNode->KeyCount, pSibling, 0, pSibling->KeyCount );
if( pNode->Leaf )
pNode->KeyCount += pSibling->KeyCount;
else
{
MIX_COPY_CHILDS_EXTERNAL( pTag, pNode, pNode->KeyCount, pSibling, 0, pSibling->KeyCount );
for( i = 0; i < pSibling->KeyCount; i++ )
pNode->Child[ pNode->KeyCount++ ]->Parent = pNode;
pNode->Child[ pNode->KeyCount ] = pSibling->Child[ i ];
pNode->Child[ pNode->KeyCount ]->Parent = pNode;
}
hb_xfree( pSibling );
pParent->Child[ j + 1 ] = pNode;
hb_mixTagDelKeyNode( pTag, pParent, j );
pNode = pParent;
}
}
else
{
/* Adjust root */
if( ! pNode->KeyCount && ! pNode->Leaf )
{
pTag->Root = pNode->Child[ 0 ];
pTag->Root->Parent = NULL;
hb_xfree( pNode );
}
return;
}
}
}
static void hb_mixTagDelKeyPos( PMIXTAG pTag, PMIXNODE pNode, unsigned int uiPos )
{
if( pNode->Leaf )
{
hb_mixTagDelKeyNode( pTag, pNode, uiPos );
hb_mixTagNodeAdjust( pTag, pNode );
}
else
{
PMIXNODE pLeaf;
pLeaf = pNode->Child[ uiPos + 1 ];
while( ! pLeaf->Leaf )
pLeaf = pLeaf->Child[ 0 ];
MIX_COPY_KEYS_EXTERNAL( pTag, pNode, uiPos, pLeaf, 0, 1 );
hb_mixTagDelKeyNode( pTag, pLeaf, 0 );
hb_mixTagNodeAdjust( pTag, pLeaf );
}
}
static HB_BOOL hb_mixTagDelKey( PMIXTAG pTag, PMIXKEY pKey )
{
PMIXNODE pNode;
unsigned int ui;
int i;
i = hb_mixTagFindKey( pTag, pKey, pTag->uiKeyLen, &pNode, &ui, HB_FALSE );
if( i )
return HB_FALSE;
hb_mixTagDelKeyPos( pTag, pNode, ui );
return HB_TRUE;
}
static PMIXTAG hb_mixTagCreate( const char * szTagName, PHB_ITEM pKeyExpr, PHB_ITEM pKeyItem, PHB_ITEM pForItem, PHB_ITEM pWhileItem, HB_BYTE bType, unsigned int uiKeyLen, SQLMIXAREAP pArea )
{
PMIXTAG pTag;
PMIXKEY pKey = NULL;
LPDBORDERCONDINFO pOrdCondInfo = pArea->sqlarea.area.lpdbOrdCondInfo;
HB_ULONG ulStartRec, ulNextCount = 0;
HB_LONG lStep = 0;
PHB_ITEM pItem, pEvalItem = NULL;
pTag = ( PMIXTAG ) hb_xgrabz( sizeof( MIXTAG ) );
pTag->pArea = pArea;
pTag->szName = ( char * ) hb_xgrab( MIX_MAXTAGNAMELEN + 1 );
hb_strncpyUpperTrim( pTag->szName, szTagName, MIX_MAXTAGNAMELEN );
pTag->szKeyExpr = ( char * ) hb_xgrab( hb_itemGetCLen( pKeyExpr ) + 1 );
hb_strncpyTrim( pTag->szKeyExpr, hb_itemGetCPtr( pKeyExpr ), hb_itemGetCLen( pKeyExpr ) );
/* TODO: FOR expression */
pTag->szForExpr = NULL;
pTag->pKeyItem = pKeyItem;
pTag->pForItem = pForItem;
pTag->bType = bType;
pTag->uiKeyLen = uiKeyLen;
pTag->uiTotalLen = sizeof( MIXKEY ) + pTag->uiKeyLen;
/* Use national support */
if( bType == 'C' )
{
if( pArea->sqlarea.area.cdPage &&
! HB_CDP_ISBINSORT( pArea->sqlarea.area.cdPage ) )
pTag->pCodepage = pArea->sqlarea.area.cdPage;
}
pTag->Root = hb_mixTagCreateNode( pTag, HB_TRUE );
ulStartRec = 0;
if( pOrdCondInfo )
{
pEvalItem = pOrdCondInfo->itmCobEval;
lStep = pOrdCondInfo->lStep;
}
if( ! pOrdCondInfo || pOrdCondInfo->fAll )
pArea->pTag = NULL;
else
{
if( pOrdCondInfo->itmRecID )
ulStartRec = hb_itemGetNL( pOrdCondInfo->itmRecID );
if( ulStartRec )
ulNextCount = 1;
else if( pOrdCondInfo->fRest || pOrdCondInfo->lNextCount > 0 )
{
if( pOrdCondInfo->itmStartRecID )
ulStartRec = hb_itemGetNL( pOrdCondInfo->itmStartRecID );
if( ! ulStartRec )
ulStartRec = pArea->sqlarea.ulRecNo;
if( pArea->sqlarea.area.lpdbOrdCondInfo->lNextCount > 0 )
ulNextCount = pOrdCondInfo->lNextCount;
}
else if( ! pOrdCondInfo->fUseCurrent )
pArea->pTag = NULL;
}
if( ulStartRec == 0 && pArea->pTag == NULL )
ulStartRec = 1;
if( ulStartRec )
SELF_GOTO( &pArea->sqlarea.area, ulStartRec );
else
SELF_GOTOP( &pArea->sqlarea.area );
while( ! pArea->sqlarea.area.fEof )
{
if( pEvalItem )
{
if( lStep >= pOrdCondInfo->lStep )
{
lStep = 0;
if( ! hb_mixEvalCond( NULL, pEvalItem ) )
break;
}
++lStep;
}
if( pWhileItem && ! hb_mixEvalCond( NULL, pWhileItem ) )
break;
if( pForItem == NULL || hb_mixEvalCond( NULL, pForItem ) )
{
pItem = hb_vmEvalBlockOrMacro( pKeyItem );
pKey = hb_mixKeyPutItem( pKey, pItem, pArea->sqlarea.ulRecNo, pTag );
hb_mixTagAddKey( pTag, pKey );
}
if( ulNextCount )
{
ulNextCount--;
if( ! ulNextCount )
break;
}
if( SELF_SKIPRAW( &pArea->sqlarea.area, 1 ) == HB_FAILURE )
break;
}
if( pKey )
hb_mixKeyFree( pKey );
return pTag;
}
static void hb_mixTagDestroyNode( PMIXNODE pNode )
{
if( ! pNode->Leaf )
{
unsigned int ui;
for( ui = 0; ui <= pNode->KeyCount; ui++ )
hb_mixTagDestroyNode( pNode->Child[ ui ] );
}
hb_xfree( pNode );
}
static void hb_mixTagDestroy( PMIXTAG pTag )
{
if( pTag->szName )
hb_xfree( pTag->szName );
if( pTag->szKeyExpr )
hb_xfree( pTag->szKeyExpr );
if( pTag->szForExpr )
hb_xfree( pTag->szForExpr );
if( pTag->pKeyItem )
hb_vmDestroyBlockOrMacro( pTag->pKeyItem );
if( pTag->pForItem )
hb_vmDestroyBlockOrMacro( pTag->pForItem );
if( pTag->Root )
hb_mixTagDestroyNode( pTag->Root );
if( pTag->HotKey )
hb_mixKeyFree( pTag->HotKey );
hb_xfree( pTag );
}
static void hb_mixTagGoTop( PMIXTAG pTag )
{
PMIXNODE pNode;
pNode = pTag->Root;
while( ! pNode->Leaf )
pNode = pNode->Child[ 0 ];
if( ! pNode->KeyCount )
{
pTag->fEof = HB_TRUE;
return;
}
pTag->fEof = HB_FALSE;
pTag->CurNode = pNode;
pTag->CurPos = 0;
pTag->CurKey = MIX_KEY( pTag, pTag->CurNode, 0 );
}
static void hb_mixTagGoBottom( PMIXTAG pTag )
{
PMIXNODE pNode;
pNode = pTag->Root;
while( ! pNode->Leaf )
pNode = pNode->Child[ pNode->KeyCount ];
if( ! pNode->KeyCount )
{
pTag->fEof = HB_TRUE;
return;
}
pTag->fEof = HB_FALSE;
pTag->CurNode = pNode;
pTag->CurPos = pNode->KeyCount - 1;
pTag->CurKey = MIX_KEY( pTag, pTag->CurNode, pTag->CurPos );
}
static void hb_mixTagSkip( PMIXTAG pTag, HB_LONG lSkip )
{
PMIXNODE pNode, pNode2;
unsigned int uiPos, uiPos2;
pNode = pTag->CurNode;
uiPos = pTag->CurPos;
/* printf("hb_mixTagSkip: CurNode=%p, CurPos=%d lSkip=%d\n", pNode, uiPos, lSkip ); */
if( lSkip > 0 )
{
pTag->fBof = HB_FALSE;
while( ! pTag->fEof && lSkip > 0 )
{
if( pNode->Leaf )
{
if( ( HB_LONG ) ( pNode->KeyCount - 1 - uiPos ) >= lSkip )
{
uiPos += lSkip;
lSkip = 0;
}
else if( pNode->KeyCount - 1 > uiPos )
{
lSkip -= ( HB_LONG ) ( pNode->KeyCount - 1 - uiPos );
uiPos = pNode->KeyCount - 1;
}
if( lSkip )
{
do
{
if( pNode->Parent )
uiPos = hb_mixTagNodeParentIndex( pNode );
pNode = pNode->Parent;
}
while( pNode && uiPos == pNode->KeyCount );
if( pNode )
lSkip--;
else
pTag->fEof = HB_TRUE;
}
}
else
{
pNode = pNode->Child[ uiPos + 1 ];
while( ! pNode->Leaf )
pNode = pNode->Child[ 0 ];
uiPos = 0;
lSkip--;
}
}
}
else if( lSkip < 0 )
{
lSkip = -lSkip;
/* This is not needed. skip(-1) from Eof is processed inside sqlmixSkipRaw */
#if 0
if( pTag->fEof )
{
hb_mixTagGoBottom( pTag );
lSkip--;
pTag->fBof = pTag->fEof;
}
#endif
pTag->fBof = pTag->fEof;
while( ! pTag->fBof && lSkip > 0 )
{
if( pNode->Leaf )
{
if( ( HB_LONG ) uiPos >= lSkip )
{
uiPos -= lSkip;
lSkip = 0;
}
else if( uiPos )
{
lSkip -= uiPos;
uiPos = 0;
}
if( lSkip )
{
pNode2 = pNode;
uiPos2 = uiPos;
do
{
if( pNode->Parent )
uiPos = hb_mixTagNodeParentIndex( pNode );
pNode = pNode->Parent;
}
while( pNode && uiPos == 0 );
if( pNode )
{
uiPos--;
lSkip--;
}
else
{
pNode = pNode2;
uiPos = uiPos2;
pTag->fBof = HB_TRUE;
}
}
}
else
{
do
{
pNode = pNode->Child[ uiPos ];
uiPos = pNode->KeyCount;
}
while( ! pNode->Leaf );
uiPos--;
lSkip--;
}
}
}
if( ! pTag->fEof )
{
pTag->CurNode = pNode;
pTag->CurPos = uiPos;
pTag->CurKey = MIX_KEY( pTag, pNode, uiPos );
}
}
/* --- Misc functions --- */
/* hb_mix*() */
static PMIXTAG hb_mixFindTag( SQLMIXAREAP pArea, PHB_ITEM pOrder )
{
PMIXTAG pTag;
if( HB_IS_NUMBER( pOrder ) )
{
int iOrder, iCurr = 0;
iOrder = hb_itemGetNI( pOrder );
pTag = pArea->pTagList;
while( pTag && iOrder != ++iCurr )
pTag = pTag->pNext;
}
else
{
char szTag[ MIX_MAXTAGNAMELEN + 1 ];
hb_strncpyUpperTrim( szTag, hb_itemGetCPtr( pOrder ), MIX_MAXTAGNAMELEN );
pTag = pArea->pTagList;
while( pTag && hb_stricmp( szTag, pTag->szName ) )
pTag = pTag->pNext;
}
return pTag;
}
/* --- */
static HB_ULONG hb_mixTagNodeKeyCount( PMIXNODE pNode )
{
HB_ULONG ulKeyCount = pNode->KeyCount;
if( ! pNode->Leaf )
{
unsigned int ui;
for( ui = 0; ui <= pNode->KeyCount; ui++ )
ulKeyCount += hb_mixTagNodeKeyCount( pNode->Child[ ui ] );
}
return ulKeyCount;
}
static HB_BOOL hb_mixCheckRecordFilter( SQLMIXAREAP pArea, HB_ULONG ulRecNo )
{
HB_BOOL lResult = HB_FALSE;
if( pArea->sqlarea.area.dbfi.itmCobExpr || hb_setGetDeleted() )
{
if( pArea->sqlarea.ulRecNo != ulRecNo || pArea->sqlarea.lpdbPendingRel )
SELF_GOTO( &pArea->sqlarea.area, ulRecNo );
if( hb_setGetDeleted() )
SUPER_DELETED( &pArea->sqlarea.area, &lResult );
if( ! lResult && pArea->sqlarea.area.dbfi.itmCobExpr )
{
PHB_ITEM pResult = hb_vmEvalBlock( pArea->sqlarea.area.dbfi.itmCobExpr );
lResult = HB_IS_LOGICAL( pResult ) && ! hb_itemGetL( pResult );
}
}
return ! lResult;
}
static HB_ULONG hb_mixDBOIKeyCount( PMIXTAG pTag, HB_BOOL fFilter )
{
HB_ULONG ulKeyCount;
if( ! pTag )
return 0;
if( fFilter && pTag->pArea->sqlarea.area.dbfi.fFilter )
{
PMIXNODE pNode = pTag->CurNode;
unsigned int uiPos = pTag->CurPos;
HB_ULONG ulRecNo = pTag->pArea->sqlarea.ulRecNo;
ulKeyCount = 0;
hb_mixTagGoTop( pTag );
while( ! pTag->fEof )
{
if( hb_mixCheckRecordFilter( pTag->pArea, pTag->CurKey->rec ) )
ulKeyCount++;
hb_mixTagSkip( pTag, 1 );
}
hb_mixTagSetCurrent( pTag, pNode, uiPos );
SELF_GOTO( &pTag->pArea->sqlarea.area, ulRecNo );
}
else
ulKeyCount = hb_mixTagNodeKeyCount( pTag->Root );
return ulKeyCount;
}
static HB_ULONG hb_mixDBOIKeyNo( PMIXTAG pTag, HB_BOOL fFilter )
{
HB_ULONG ulKeyCount;
if( ! pTag )
return 0;
if( fFilter )
ulKeyCount = 0;
else
{
PMIXNODE pNode = pTag->CurNode;
unsigned int ui, uiPos = pTag->CurPos;
ulKeyCount = 1;
while( pNode )
{
ulKeyCount += uiPos;
if( ! pNode->Leaf )
{
for( ui = 0; ui < uiPos; ui++ )
ulKeyCount += hb_mixTagNodeKeyCount( pNode->Child[ ui ] );
}
pNode = pNode->Parent;
if( pNode )
uiPos = hb_mixTagNodeParentIndex( pNode );
}
}
return ulKeyCount;
}
/* --- SQLMIX RDD METHODS --- */
static HB_ERRCODE sqlmixGoBottom( SQLMIXAREAP pArea )
{
HB_ERRCODE retval;
if( SELF_GOCOLD( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
if( ! pArea->pTag )
return SUPER_GOBOTTOM( &pArea->sqlarea.area );
if( pArea->sqlarea.lpdbPendingRel && pArea->sqlarea.lpdbPendingRel->isScoped )
SELF_FORCEREL( &pArea->sqlarea.area );
hb_mixTagGoBottom( pArea->pTag );
pArea->sqlarea.area.fTop = HB_FALSE;
pArea->sqlarea.area.fBottom = HB_TRUE;
retval = SELF_GOTO( &pArea->sqlarea.area, pArea->pTag->CurKey ? pArea->pTag->CurKey->rec : 0 );
if( retval != HB_FAILURE && pArea->sqlarea.fPositioned )
retval = SELF_SKIPFILTER( &pArea->sqlarea.area, -1 );
return retval;
}
static HB_ERRCODE sqlmixGoTop( SQLMIXAREAP pArea )
{
HB_ERRCODE retval;
if( SELF_GOCOLD( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
if( ! pArea->pTag )
return SUPER_GOTOP( &pArea->sqlarea.area );
if( pArea->sqlarea.lpdbPendingRel && pArea->sqlarea.lpdbPendingRel->isScoped )
SELF_FORCEREL( &pArea->sqlarea.area );
hb_mixTagGoTop( pArea->pTag );
pArea->sqlarea.area.fTop = HB_TRUE;
pArea->sqlarea.area.fBottom = HB_FALSE;
retval = SELF_GOTO( &pArea->sqlarea.area, pArea->pTag->CurKey ? pArea->pTag->CurKey->rec : 0 );
if( retval != HB_FAILURE && pArea->sqlarea.fPositioned )
retval = SELF_SKIPFILTER( &pArea->sqlarea.area, 1 );
return retval;
}
static HB_ERRCODE sqlmixSeek( SQLMIXAREAP pArea, HB_BOOL fSoftSeek, PHB_ITEM pItem, HB_BOOL fFindLast )
{
if( SELF_GOCOLD( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
if( ! pArea->pTag )
{
sqlmixErrorRT( pArea, EG_NOORDER, 1201, NULL, 0, EF_CANDEFAULT );
return HB_FAILURE;
}
else
{
PMIXKEY pKey;
HB_ERRCODE errCode = HB_SUCCESS;
HB_BOOL fEOF;
PMIXTAG pTag = pArea->pTag;
PMIXNODE pNode;
unsigned int uiKeyLen, ui;
if( pArea->sqlarea.lpdbPendingRel && pArea->sqlarea.lpdbPendingRel->isScoped )
SELF_FORCEREL( &pArea->sqlarea.area );
pArea->sqlarea.area.fTop = pArea->sqlarea.area.fBottom = HB_FALSE;
pArea->sqlarea.area.fEof = HB_FALSE;
pKey = hb_mixKeyPutItem( NULL, pItem, fFindLast ? ( HB_ULONG ) -1 : 0, pTag );
uiKeyLen = pTag->uiKeyLen;
if( pTag->bType == 'C' )
{
uiKeyLen = ( unsigned int ) hb_itemGetCLen( pItem );
if( uiKeyLen > pTag->uiKeyLen )
uiKeyLen = pTag->uiKeyLen;
}
hb_mixTagFindKey( pTag, pKey, uiKeyLen, &pNode, &ui, HB_TRUE );
hb_mixTagSetCurrent( pTag, pNode, ui );
if( fFindLast )
{
if( pTag->fEof )
hb_mixTagGoBottom( pTag );
else
hb_mixTagSkip( pTag, -1 );
pArea->sqlarea.area.fFound = ! pTag->fEof && ( uiKeyLen == 0 || memcmp( pTag->CurKey->val, pKey->val, ( HB_ULONG ) uiKeyLen ) == 0 );
if( ! pArea->sqlarea.area.fFound )
hb_mixTagSetCurrent( pTag, pNode, ui );
}
else
pArea->sqlarea.area.fFound = ! pTag->fEof && ( uiKeyLen == 0 || memcmp( pTag->CurKey->val, pKey->val, ( HB_ULONG ) uiKeyLen ) == 0 );
fEOF = pTag->fEof;
if( ! fEOF )
{
errCode = SELF_GOTO( &pArea->sqlarea.area, pTag->CurKey->rec );
if( errCode != HB_FAILURE && pArea->sqlarea.fPositioned )
{
errCode = SELF_SKIPFILTER( &pArea->sqlarea.area, fFindLast ? -1 : 1 );
if( errCode != HB_FAILURE && pArea->sqlarea.fPositioned )
{
pArea->sqlarea.area.fFound = ( uiKeyLen == 0 || memcmp( pTag->CurKey->val, pKey->val, ( HB_ULONG ) uiKeyLen ) == 0 );
if( ! pArea->sqlarea.area.fFound && ! fSoftSeek )
fEOF = HB_TRUE;
}
}
}
if( errCode != HB_FAILURE && fEOF )
errCode = SELF_GOTO( &pArea->sqlarea.area, 0 );
pArea->sqlarea.area.fBof = HB_FALSE;
hb_mixKeyFree( pKey );
return errCode;
}
}
static HB_ERRCODE sqlmixSkipRaw( SQLMIXAREAP pArea, HB_LONG lToSkip )
{
PMIXTAG pTag = pArea->pTag;
HB_BOOL fOut = HB_FALSE;
if( SELF_GOCOLD( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
if( ! pTag || lToSkip == 0 )
return SUPER_SKIPRAW( &pArea->sqlarea.area, lToSkip );
if( pArea->sqlarea.lpdbPendingRel )
SELF_FORCEREL( &pArea->sqlarea.area );
if( ! hb_mixTagRefreshKey( pTag ) )
{
if( lToSkip > 0 || pArea->sqlarea.fPositioned )
fOut = HB_TRUE;
else
{
hb_mixTagGoBottom( pTag );
fOut = pTag->fEof;
lToSkip++;
}
}
if( ! fOut )
hb_mixTagSkip( pTag, lToSkip );
if( SELF_GOTO( &pArea->sqlarea.area, ( pTag->fEof || fOut ) ? 0 : pTag->CurKey->rec ) != HB_SUCCESS )
return HB_FAILURE;
pArea->sqlarea.area.fEof = pTag->fEof;
pArea->sqlarea.area.fBof = pTag->fBof;
return HB_SUCCESS;
}
static HB_ERRCODE sqlmixGoCold( SQLMIXAREAP pArea )
{
HB_BOOL fRecordChanged = pArea->sqlarea.fRecordChanged;
HB_BOOL fAppend = pArea->sqlarea.fAppend;
if( SUPER_GOCOLD( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
if( fRecordChanged && pArea->pTagList )
{
PMIXTAG pTag;
HB_BOOL fAdd, fDel;
LPDBRELINFO lpdbPendingRel;
lpdbPendingRel = pArea->sqlarea.lpdbPendingRel;
pArea->sqlarea.lpdbPendingRel = NULL;
pTag = pArea->pTagList;
while( pTag )
{
if( ! pTag->fCustom )
{
PMIXKEY pKey = hb_mixKeyEval( NULL, pTag );
if( pTag->pForItem != NULL )
fAdd = hb_mixEvalCond( pArea, pTag->pForItem );
else
fAdd = HB_TRUE;
if( fAppend )
fDel = HB_FALSE;
else
{
if( hb_mixKeyCompare( pTag, pKey, pTag->HotKey, pTag->uiKeyLen ) == 0 )
{
fDel = ! fAdd && pTag->HotFor;
fAdd = fAdd && ! pTag->HotFor;
}
else
fDel = pTag->HotFor;
}
if( fDel )
hb_mixTagDelKey( pTag, pTag->HotKey );
if( fAdd )
hb_mixTagAddKey( pTag, pKey );
hb_mixKeyFree( pKey );
}
pTag = pTag->pNext;
}
pArea->sqlarea.lpdbPendingRel = lpdbPendingRel;
}
return HB_SUCCESS;
}
static HB_ERRCODE sqlmixGoHot( SQLMIXAREAP pArea )
{
PMIXTAG pTag;
#if 0
if( pArea->fRecordChanged )
printf( "sqlmixGoHot: multiple marking buffer as hot." );
#endif
if( SUPER_GOHOT( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
pTag = pArea->pTagList;
while( pTag )
{
if( ! pTag->fCustom )
{
pTag->HotKey = hb_mixKeyEval( pTag->HotKey, pTag );
pTag->HotFor = pTag->pForItem == NULL || hb_mixEvalCond( pArea, pTag->pForItem );
}
pTag = pTag->pNext;
}
return HB_SUCCESS;
}
static HB_ERRCODE sqlmixClose( SQLMIXAREAP pArea )
{
if( SELF_GOCOLD( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
if( SUPER_CLOSE( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
if( SELF_ORDLSTCLEAR( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
return HB_SUCCESS;
}
static HB_ERRCODE sqlmixStructSize( SQLMIXAREAP pArea, HB_USHORT * StructSize )
{
HB_SYMBOL_UNUSED( pArea );
*StructSize = sizeof( SQLMIXAREA );
return HB_SUCCESS;
}
static HB_ERRCODE sqlmixOrderListClear( SQLMIXAREAP pArea )
{
PMIXTAG pTag;
while( pArea->pTagList )
{
pTag = pArea->pTagList;
pArea->pTagList = pTag->pNext;
hb_mixTagDestroy( pTag );
}
pArea->pTag = NULL;
return HB_SUCCESS;
}
static HB_ERRCODE sqlmixOrderListFocus( SQLMIXAREAP pArea, LPDBORDERINFO pOrderInfo )
{
if( pArea->pTag )
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pArea->pTag->szName );
if( pOrderInfo->itmOrder )
pArea->pTag = hb_mixFindTag( pArea, pOrderInfo->itmOrder );
return pArea->pTag ? HB_SUCCESS : HB_FAILURE;
}
static HB_ERRCODE sqlmixOrderCreate( SQLMIXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo )
{
PMIXTAG pTagNew, pTag;
PHB_ITEM pKeyItem, pForItem = NULL, pWhileItem = NULL, pResult;
HB_ULONG ulRecNo;
HB_USHORT uiLen;
HB_BYTE bType;
/* Obtain key codeblock */
if( pOrderInfo->itmCobExpr )
pKeyItem = hb_itemNew( pOrderInfo->itmCobExpr );
else
{
if( SELF_COMPILE( &pArea->sqlarea.area, hb_itemGetCPtr( pOrderInfo->abExpr ) ) == HB_FAILURE )
return HB_FAILURE;
pKeyItem = pArea->sqlarea.area.valResult;
pArea->sqlarea.area.valResult = NULL;
}
/* Test key codeblock on EOF */
ulRecNo = pArea->sqlarea.ulRecNo;
SELF_GOTO( &pArea->sqlarea.area, 0 );
if( SELF_EVALBLOCK( &pArea->sqlarea.area, pKeyItem ) == HB_FAILURE )
{
hb_vmDestroyBlockOrMacro( pKeyItem );
SELF_GOTO( &pArea->sqlarea.area, ulRecNo );
return HB_FAILURE;
}
pResult = pArea->sqlarea.area.valResult;
pArea->sqlarea.area.valResult = NULL;
switch( hb_itemType( pResult ) )
{
case HB_IT_STRING:
case HB_IT_MEMO:
bType = 'C';
uiLen = ( HB_USHORT ) hb_itemGetCLen( pResult );
if( uiLen > MIX_MAXKEYLEN )
uiLen = MIX_MAXKEYLEN;
break;
case HB_IT_INTEGER:
case HB_IT_LONG:
case HB_IT_DOUBLE:
bType = 'N';
uiLen = 8;
break;
case HB_IT_DATE:
bType = 'D';
uiLen = 8;
break;
case HB_IT_LOGICAL:
bType = 'L';
uiLen = 1;
break;
default:
bType = 'U';
uiLen = 0;
}
hb_itemRelease( pResult );
if( bType == 'U' || uiLen == 0 )
{
hb_vmDestroyBlockOrMacro( pKeyItem );
SELF_GOTO( &pArea->sqlarea.area, ulRecNo );
sqlmixErrorRT( pArea, bType == 'U' ? EG_DATATYPE : EG_DATAWIDTH, 1026, NULL, 0, 0 );
return HB_FAILURE;
}
if( pArea->sqlarea.area.lpdbOrdCondInfo )
{
/* Obtain FOR codeblock */
if( pArea->sqlarea.area.lpdbOrdCondInfo->itmCobFor )
pForItem = hb_itemNew( pArea->sqlarea.area.lpdbOrdCondInfo->itmCobFor );
else if( pArea->sqlarea.area.lpdbOrdCondInfo->abFor )
{
if( SELF_COMPILE( &pArea->sqlarea.area, pArea->sqlarea.area.lpdbOrdCondInfo->abFor ) == HB_FAILURE )
{
hb_vmDestroyBlockOrMacro( pKeyItem );
SELF_GOTO( &pArea->sqlarea.area, ulRecNo );
return HB_FAILURE;
}
pForItem = pArea->sqlarea.area.valResult;
pArea->sqlarea.area.valResult = NULL;
}
/* Obtain WHILE codeblock */
if( pArea->sqlarea.area.lpdbOrdCondInfo->itmCobWhile )
pWhileItem = hb_itemNew( pArea->sqlarea.area.lpdbOrdCondInfo->itmCobWhile );
else if( pArea->sqlarea.area.lpdbOrdCondInfo->abWhile )
{
if( SELF_COMPILE( &pArea->sqlarea.area, pArea->sqlarea.area.lpdbOrdCondInfo->abWhile ) == HB_FAILURE )
{
hb_vmDestroyBlockOrMacro( pKeyItem );
if( pForItem )
hb_vmDestroyBlockOrMacro( pForItem );
SELF_GOTO( &pArea->sqlarea.area, ulRecNo );
return HB_FAILURE;
}
pWhileItem = pArea->sqlarea.area.valResult;
pArea->sqlarea.area.valResult = NULL;
}
}
/* Test FOR codeblock on EOF */
if( pForItem )
{
if( SELF_EVALBLOCK( &pArea->sqlarea.area, pForItem ) == HB_FAILURE )
{
hb_vmDestroyBlockOrMacro( pKeyItem );
hb_vmDestroyBlockOrMacro( pForItem );
if( pWhileItem )
hb_vmDestroyBlockOrMacro( pWhileItem );
SELF_GOTO( &pArea->sqlarea.area, ulRecNo );
return HB_FAILURE;
}
if( ( hb_itemType( pArea->sqlarea.area.valResult ) & HB_IT_LOGICAL ) == 0 )
{
hb_itemRelease( pArea->sqlarea.area.valResult );
pArea->sqlarea.area.valResult = 0;
hb_vmDestroyBlockOrMacro( pKeyItem );
hb_vmDestroyBlockOrMacro( pForItem );
if( pWhileItem )
hb_vmDestroyBlockOrMacro( pWhileItem );
SELF_GOTO( &pArea->sqlarea.area, ulRecNo );
sqlmixErrorRT( pArea, EG_DATATYPE, EDBF_INVALIDFOR, NULL, 0, 0 );
return HB_FAILURE;
}
hb_itemRelease( pArea->sqlarea.area.valResult );
pArea->sqlarea.area.valResult = 0;
}
/* TODO: WHILE condition is not tested, like in DBFCDX. Why? Compatibility with Clipper? */
SELF_GOTO( &pArea->sqlarea.area, ulRecNo );
pTagNew = hb_mixTagCreate( pOrderInfo->atomBagName, pOrderInfo->abExpr, pKeyItem, pForItem, pWhileItem, bType, uiLen, pArea );
if( pWhileItem )
hb_vmDestroyBlockOrMacro( pWhileItem );
/* Append the tag to the end of list */
if( pArea->pTagList )
{
pTag = pArea->pTagList;
while( pTag->pNext )
pTag = pTag->pNext;
pTag->pNext = pTagNew;
}
else
pArea->pTagList = pTagNew;
pArea->pTag = pTagNew;
return HB_SUCCESS;
}
static HB_ERRCODE sqlmixOrderInfo( SQLMIXAREAP pArea, HB_USHORT uiIndex, LPDBORDERINFO pOrderInfo )
{
PMIXTAG pTag;
HB_USHORT uiTag = 0;
switch( uiIndex )
{
case DBOI_EVALSTEP:
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult,
pArea->sqlarea.area.lpdbOrdCondInfo ? pArea->sqlarea.area.lpdbOrdCondInfo->lStep : 0 );
return HB_SUCCESS;
case DBOI_ORDERCOUNT:
pTag = pArea->pTagList;
while( pTag )
{
pTag = pTag->pNext;
uiTag++;
}
pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag );
return HB_SUCCESS;
}
if( SELF_GOCOLD( &pArea->sqlarea.area ) == HB_FAILURE )
return HB_FAILURE;
if( pOrderInfo->itmOrder )
pTag = hb_mixFindTag( pArea, pOrderInfo->itmOrder );
else
pTag = pArea->pTag;
switch( uiIndex )
{
case DBOI_CONDITION:
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, ( pTag ? pTag->szForExpr : NULL ) );
if( pTag && pOrderInfo->itmNewVal && HB_IS_STRING( pOrderInfo->itmNewVal ) )
{
if( pTag->szForExpr != NULL )
{
hb_xfree( pTag->szForExpr );
pTag->szForExpr = NULL;
}
if( pTag->pForItem != NULL )
{
hb_vmDestroyBlockOrMacro( pTag->pForItem );
pTag->pForItem = NULL;
}
if( hb_itemGetCLen( pOrderInfo->itmNewVal ) > 0 )
{
const char * pForExpr = hb_itemGetCPtr( pOrderInfo->itmNewVal );
if( SELF_COMPILE( &pArea->sqlarea.area, pForExpr ) == HB_SUCCESS )
{
PHB_ITEM pForItem = pArea->sqlarea.area.valResult;
pArea->sqlarea.area.valResult = NULL;
if( SELF_EVALBLOCK( &pArea->sqlarea.area, pForItem ) == HB_SUCCESS )
{
if( hb_itemType( pArea->sqlarea.area.valResult ) & HB_IT_LOGICAL )
{
pTag->szForExpr = hb_strdup( pForExpr );
pTag->pForItem = pForItem;
pForItem = NULL;
}
hb_itemRelease( pArea->sqlarea.area.valResult );
pArea->sqlarea.area.valResult = NULL;
}
if( pForItem )
hb_vmDestroyBlockOrMacro( pForItem );
}
}
}
break;
case DBOI_EXPRESSION:
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pTag ? pTag->szKeyExpr : NULL );
break;
case DBOI_POSITION:
case DBOI_KEYNORAW:
if( pOrderInfo->itmNewVal && HB_IS_NUMERIC( pOrderInfo->itmNewVal ) )
{
/* TODO */
#if 0
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult,
hb_cdxDBOIKeyGoto( pArea, pTag,
hb_itemGetNL( pOrderInfo->itmNewVal ), uiIndex == DBOI_POSITION ) == HB_SUCCESS );
#endif
}
else
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult,
hb_mixDBOIKeyNo( pTag, uiIndex == DBOI_POSITION ) );
break;
case DBOI_KEYCOUNT:
case DBOI_KEYCOUNTRAW:
pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult,
hb_mixDBOIKeyCount( pTag, uiIndex == DBOI_KEYCOUNT ) );
break;
/* TODO */
#if 0
case DBOI_FINDREC:
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult,
hb_cdxDBOIFindRec( pArea, pTag,
hb_itemGetNL( pOrderInfo->itmNewVal ), HB_FALSE ) );
break;
case DBOI_FINDRECCONT:
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult,
hb_cdxDBOIFindRec( pArea, pTag,
hb_itemGetNL( pOrderInfo->itmNewVal ), HB_TRUE ) );
break;
#endif
case DBOI_NAME:
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pTag ? pTag->szName : NULL );
break;
case DBOI_NUMBER:
pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag ); /* otherwise */
break;
case DBOI_ISCOND:
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, pTag && pTag->szForExpr != NULL );
break;
case DBOI_ISDESC:
case DBOI_UNIQUE:
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, HB_FALSE );
break;
case DBOI_SCOPETOP:
case DBOI_SCOPEBOTTOM:
if( pOrderInfo->itmResult )
hb_itemClear( pOrderInfo->itmResult );
break;
case DBOI_KEYTYPE:
if( pTag )
{
char szType[ 2 ];
szType[ 0 ] = ( char ) pTag->bType;
szType[ 1 ] = 0;
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, szType );
}
else
pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, NULL );
break;
case DBOI_KEYSIZE:
pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, pTag ? pTag->uiKeyLen : 0 );
break;
case DBOI_KEYDEC:
pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, 0 );
break;
/* TODO */
#if 0
case DBOI_KEYVAL:
hb_itemClear( pOrderInfo->itmResult );
if( pArea->sqlarea.lpdbPendingRel )
SELF_FORCEREL( &pArea->sqlarea.area );
if( pTag && pArea->sqlarea.fPositioned )
{
if( pTag->CurKey->rec != pArea->sqlarea.ulRecNo )
{
hb_cdxIndexLockRead( pTag->pIndex );
hb_cdxCurKeyRefresh( pArea, pTag );
hb_cdxIndexUnLockRead( pTag->pIndex );
}
if( pTag->CurKey->rec == pArea->sqlarea.ulRecNo )
pOrderInfo->itmResult = hb_cdxKeyGetItem( pTag->CurKey,
pOrderInfo->itmResult, pTag, HB_TRUE );
}
break;
case DBOI_CUSTOM:
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? pTag->fCustom : HB_FALSE ) );
if( pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal )
&& hb_itemGetL( pOrderInfo->itmNewVal ) )
pTag->fCustom = HB_TRUE;
break;
case DBOI_KEYADD:
if( ! pTag )
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, HB_FALSE );
else
{
if( pTag->fCustom )
{
if( pArea->sqlarea.lpdbPendingRel )
SELF_FORCEREL( &pArea->sqlarea.area );
if( ! pArea->sqlarea.fPositioned ||
( pTag->pForItem &&
! hb_cdxEvalCond( pArea, pTag->pForItem, HB_TRUE ) ) )
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, HB_FALSE );
else
{
LPCDXKEY pKey;
hb_cdxIndexLockWrite( pTag->pIndex );
if( pOrderInfo->itmNewVal && ! HB_IS_NIL( pOrderInfo->itmNewVal ) )
pKey = hb_cdxKeyPutItem( NULL, pOrderInfo->itmNewVal, pArea->sqlarea.ulRecNo, pTag, HB_TRUE, HB_TRUE );
else
pKey = hb_cdxKeyEval( NULL, pTag );
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult,
hb_cdxTagKeyAdd( pTag, pKey ) );
hb_cdxIndexUnLockWrite( pTag->pIndex );
hb_cdxKeyFree( pKey );
}
}
else
sqlmixErrorRT( pArea, 0, 1052, NULL, 0, 0 );
}
break;
case DBOI_KEYDELETE:
if( ! pTag )
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, HB_FALSE );
else
{
if( pTag->Custom )
{
if( pArea->sqlarea.lpdbPendingRel )
SELF_FORCEREL( &pArea->sqlarea.area );
if( ! pArea->sqlarea.fPositioned ||
( pTag->pForItem &&
! hb_cdxEvalCond( pArea, pTag->pForItem, HB_TRUE ) ) )
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, HB_FALSE );
else
{
LPCDXKEY pKey;
hb_cdxIndexLockWrite( pTag->pIndex );
if( pOrderInfo->itmNewVal && ! HB_IS_NIL( pOrderInfo->itmNewVal ) )
pKey = hb_cdxKeyPutItem( NULL, pOrderInfo->itmNewVal, pArea->sqlarea.ulRecNo, pTag, HB_TRUE, HB_TRUE );
else
pKey = hb_cdxKeyEval( NULL, pTag );
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult,
hb_cdxTagKeyDel( pTag, pKey ) );
hb_cdxIndexUnLockWrite( pTag->pIndex );
hb_cdxKeyFree( pKey );
}
}
else
sqlmixErrorRT( pArea, 0, 1052, NULL, 0, 0 );
}
break;
#endif
case DBOI_SHARED:
case DBOI_ISREADONLY:
pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, HB_FALSE );
break;
default:
return SUPER_ORDINFO( &pArea->sqlarea.area, uiIndex, pOrderInfo );
}
return HB_SUCCESS;
}
static HB_ERRCODE sqlmixInit( LPRDDNODE pRDD )
{
/* This empty method is used to avoid duplicated sqlbase init call */
HB_SYMBOL_UNUSED( pRDD );
return HB_SUCCESS;
}
static HB_ERRCODE sqlmixExit( LPRDDNODE pRDD )
{
/* This empty method is used to avoid duplicated sqlbase exit call */
HB_SYMBOL_UNUSED( pRDD );
return HB_SUCCESS;
}
static RDDFUNCS sqlmixTable =
{ ( DBENTRYP_BP ) NULL, /* sqlmixBof */
( DBENTRYP_BP ) NULL, /* sqlmixEof */
( DBENTRYP_BP ) NULL, /* sqlmixFound */
( DBENTRYP_V ) sqlmixGoBottom,
( DBENTRYP_UL ) NULL, /* sqlmixGoTo */
( DBENTRYP_I ) NULL, /* sqlmixGoToId */
( DBENTRYP_V ) sqlmixGoTop,
( DBENTRYP_BIB ) sqlmixSeek,
( DBENTRYP_L ) NULL, /* sqlmixSkip */
( DBENTRYP_L ) NULL, /* sqlmixSkipFilter */
( DBENTRYP_L ) sqlmixSkipRaw,
( DBENTRYP_VF ) NULL, /* sqlmixAddField */
( DBENTRYP_B ) NULL, /* sqlmixAppend */
( DBENTRYP_I ) NULL, /* sqlmixCreateFields */
( DBENTRYP_V ) NULL, /* sqlmixDeleteRec */
( DBENTRYP_BP ) NULL, /* sqlmixDeleted */
( DBENTRYP_SP ) NULL, /* sqlmixFieldCount */
( DBENTRYP_VF ) NULL, /* sqlmixFieldDisplay */
( DBENTRYP_SSI ) NULL, /* sqlmixFieldInfo */
( DBENTRYP_SCP ) NULL, /* sqlmixFieldName */
( DBENTRYP_V ) NULL, /* sqlmixFlush */
( DBENTRYP_PP ) NULL, /* sqlmixGetRec */
( DBENTRYP_SI ) NULL, /* sqlmixGetValue */
( DBENTRYP_SVL ) NULL, /* sqlmixGetVarLen */
( DBENTRYP_V ) sqlmixGoCold,
( DBENTRYP_V ) sqlmixGoHot,
( DBENTRYP_P ) NULL, /* sqlmixPutRec */
( DBENTRYP_SI ) NULL, /* sqlmixPutValue */
( DBENTRYP_V ) NULL, /* sqlmixRecall */
( DBENTRYP_ULP ) NULL, /* sqlmixRecCount */
( DBENTRYP_ISI ) NULL, /* sqlmixRecInfo */
( DBENTRYP_ULP ) NULL, /* sqlmixRecNo */
( DBENTRYP_I ) NULL, /* sqlmixRecId */
( DBENTRYP_S ) NULL, /* sqlmixSetFieldExtent */
( DBENTRYP_CP ) NULL, /* sqlmixAlias */
( DBENTRYP_V ) sqlmixClose,
( DBENTRYP_VO ) NULL, /* sqlmixCreate */
( DBENTRYP_SI ) NULL, /* sqlmixInfo */
( DBENTRYP_V ) NULL, /* sqlmixNewArea */
( DBENTRYP_VO ) NULL, /* sqlmixOpen */
( DBENTRYP_V ) NULL, /* sqlmixRelease */
( DBENTRYP_SP ) sqlmixStructSize,
( DBENTRYP_CP ) NULL, /* sqlmixSysName */
( DBENTRYP_VEI ) NULL, /* sqlmixEval */
( DBENTRYP_V ) NULL, /* sqlmixPack */
( DBENTRYP_LSP ) NULL, /* sqlmixPackRec */
( DBENTRYP_VS ) NULL, /* sqlmixSort */
( DBENTRYP_VT ) NULL, /* sqlmixTrans */
( DBENTRYP_VT ) NULL, /* sqlmixTransRec */
( DBENTRYP_V ) NULL, /* sqlmixZap */
( DBENTRYP_VR ) NULL, /* sqlmixChildEnd */
( DBENTRYP_VR ) NULL, /* sqlmixChildStart */
( DBENTRYP_VR ) NULL, /* sqlmixChildSync */
( DBENTRYP_V ) NULL, /* sqlmixSyncChildren */
( DBENTRYP_V ) NULL, /* sqlmixClearRel */
( DBENTRYP_V ) NULL, /* sqlmixForceRel */
( DBENTRYP_SSP ) NULL, /* sqlmixRelArea */
( DBENTRYP_VR ) NULL, /* sqlmixRelEval */
( DBENTRYP_SI ) NULL, /* sqlmixRelText */
( DBENTRYP_VR ) NULL, /* sqlmixSetRel */
( DBENTRYP_VOI ) NULL, /* sqlmixOrderListAdd */
( DBENTRYP_V ) sqlmixOrderListClear,
( DBENTRYP_VOI ) NULL, /* sqlmixOrderListDelete */
( DBENTRYP_VOI ) sqlmixOrderListFocus,
( DBENTRYP_V ) NULL, /* sqlmixOrderListRebuild */
( DBENTRYP_VOO ) NULL, /* sqlmixOrderCondition */
( DBENTRYP_VOC ) sqlmixOrderCreate,
( DBENTRYP_VOI ) NULL, /* sqlmixOrderDestroy */
( DBENTRYP_SVOI ) sqlmixOrderInfo,
( DBENTRYP_V ) NULL, /* sqlmixClearFilter */
( DBENTRYP_V ) NULL, /* sqlmixClearLocate */
( DBENTRYP_V ) NULL, /* sqlmixClearScope */
( DBENTRYP_VPLP ) NULL, /* sqlmixCountScope */
( DBENTRYP_I ) NULL, /* sqlmixFilterText */
( DBENTRYP_SI ) NULL, /* sqlmixScopeInfo */
( DBENTRYP_VFI ) NULL, /* sqlmixSetFilter */
( DBENTRYP_VLO ) NULL, /* sqlmixSetLocate */
( DBENTRYP_VOS ) NULL, /* sqlmixSetScope */
( DBENTRYP_VPL ) NULL, /* sqlmixSkipScope */
( DBENTRYP_B ) NULL, /* sqlmixLocate */
( DBENTRYP_CC ) NULL, /* sqlmixCompile */
( DBENTRYP_I ) NULL, /* sqlmixError */
( DBENTRYP_I ) NULL, /* sqlmixEvalBlock */
( DBENTRYP_VSP ) NULL, /* sqlmixRawLock */
( DBENTRYP_VL ) NULL, /* sqlmixLock */
( DBENTRYP_I ) NULL, /* sqlmixUnLock */
( DBENTRYP_V ) NULL, /* sqlmixCloseMemFile */
( DBENTRYP_VO ) NULL, /* sqlmixCreateMemFile */
( DBENTRYP_SCCS ) NULL, /* sqlmixGetValueFile */
( DBENTRYP_VO ) NULL, /* sqlmixOpenMemFile */
( DBENTRYP_SCCS ) NULL, /* sqlmixPutValueFile */
( DBENTRYP_V ) NULL, /* sqlmixReadDBHeader */
( DBENTRYP_V ) NULL, /* sqlmixWriteDBHeader */
( DBENTRYP_R ) sqlmixInit,
( DBENTRYP_R ) sqlmixExit,
( DBENTRYP_RVVL ) NULL, /* sqlmixDrop */
( DBENTRYP_RVVL ) NULL, /* sqlmixExists */
( DBENTRYP_RVVVL ) NULL, /* sqlmixRename */
( DBENTRYP_RSLV ) NULL, /* sqlmixRddInfo */
( DBENTRYP_SVP ) NULL, /* sqlmixWhoCares */
};
/* force SQLBASE linking */
HB_FUNC_TRANSLATE( SQLMIX, SQLBASE )
HB_FUNC_STATIC( SQLMIX_GETFUNCTABLE )
{
RDDFUNCS * pTable;
HB_USHORT * puiCount, * puiSuperRddId, uiRddId;
puiCount = ( HB_USHORT * ) hb_parptr( 1 );
pTable = ( RDDFUNCS * ) hb_parptr( 2 );
uiRddId = ( HB_USHORT ) hb_parni( 4 );
puiSuperRddId = ( HB_USHORT * ) hb_parptr( 5 );
if( pTable )
{
HB_ERRCODE errCode;
if( puiCount )
*puiCount = RDDFUNCSCOUNT;
errCode = hb_rddInheritEx( pTable, &sqlmixTable, &sqlmixSuper, "SQLBASE", puiSuperRddId );
if( errCode == HB_SUCCESS )
s_uiRddIdSQLMIX = uiRddId;
hb_retni( errCode );
}
else
hb_retni( HB_FAILURE );
}
static void hb_sqlmixRddInit( void * cargo )
{
HB_SYMBOL_UNUSED( cargo );
if( hb_rddRegister( "SQLBASE", RDT_FULL ) > 1 ||
hb_rddRegister( "SQLMIX", RDT_FULL ) > 1 )
hb_errInternal( HB_EI_RDDINVALID, NULL, NULL, NULL );
}
HB_INIT_SYMBOLS_BEGIN( sqlmix__InitSymbols )
{
"SQLMIX", { HB_FS_PUBLIC | HB_FS_LOCAL }, { HB_FUNCNAME( SQLMIX ) }, NULL
},
{ "SQLMIX_GETFUNCTABLE", { HB_FS_PUBLIC | HB_FS_LOCAL }, { HB_FUNCNAME( SQLMIX_GETFUNCTABLE ) }, NULL }
HB_INIT_SYMBOLS_END( sqlmix__InitSymbols )
HB_CALL_ON_STARTUP_BEGIN( _hb_sqlmix_rdd_init_ )
hb_vmAtInit( hb_sqlmixRddInit, NULL );
HB_CALL_ON_STARTUP_END( _hb_sqlmix_rdd_init_ )
#if defined( HB_PRAGMA_STARTUP )
#pragma startup sqlmix__InitSymbols
#pragma startup _hb_sqlmix_rdd_init_
#elif defined( HB_DATASEG_STARTUP )
#define HB_DATASEG_BODY HB_DATASEG_FUNC( sqlmix__InitSymbols ) \
HB_DATASEG_FUNC( _hb_sqlmix_rdd_init_ )
#include "hbiniseg.h"
#endif