/*
 * SQL Base 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 "hbapiitm.h"
#include "hbvm.h"
#include "hbset.h"
#include "hbrddsql.h"
#include "rddsys.ch"

#include "hbtrace.h"

#define SUPERTABLE              ( &sqlbaseSuper )

#define CONNECTION_LIST_EXPAND  4

static HB_USHORT s_rddidSQLBASE = 0;

static SQLDDCONNECTION ** s_pConnection = NULL;
static HB_ULONG s_ulConnectionCount     = 0;
static HB_ULONG s_ulConnectionCurrent   = 0;

static char *     s_szError = NULL;
static HB_ERRCODE s_errCode = 0;

static char *        s_szQuery        = NULL;
static PHB_ITEM      s_pItemNewID     = NULL;
static unsigned long s_ulAffectedRows = 0;

static RDDFUNCS sqlbaseSuper;


void hb_rddsqlSetError( HB_ERRCODE errCode, const char * szError, const char * szQuery, PHB_ITEM pItem, unsigned long ulAffectedRows )
{
   s_errCode = errCode;

   if( s_szError )
   {
      hb_xfree( s_szError );
      s_szError = NULL;
   }
   if( szError )
      s_szError = hb_strdup( szError );

   if( s_szQuery )
   {
      hb_xfree( s_szQuery );
      s_szQuery = NULL;
   }
   if( szQuery )
      s_szQuery = hb_strdup( szQuery );

   if( pItem )
      hb_itemCopy( s_pItemNewID, pItem );
   else
      hb_itemClear( s_pItemNewID );

   s_ulAffectedRows = ulAffectedRows;
}


static HB_ERRCODE hb_errRT_SQLBASE( HB_ERRCODE errGenCode, HB_ERRCODE errSubCode, const char * szDescription, const char * szOperation )
{
   HB_ERRCODE iRet = HB_FAILURE;

   if( hb_vmRequestQuery() == 0 )
   {
      PHB_ITEM pError;
      pError = hb_errRT_New( ES_ERROR, "SQLBASE", errGenCode, errSubCode, szDescription, szOperation, 0, EF_NONE );
      iRet   = hb_errLaunch( pError );
      hb_itemRelease( pError );
   }
   return iRet;
}


/* --- NULL SDD --- */

static HB_ERRCODE sddConnect( SQLDDCONNECTION * pConnection, PHB_ITEM pItem );
static HB_ERRCODE sddDisconnect( SQLDDCONNECTION * pConnection );
static HB_ERRCODE sddExecute( SQLDDCONNECTION * pConnection, PHB_ITEM pItem );
static HB_ERRCODE sddOpen( SQLBASEAREAP pArea );
static HB_ERRCODE sddClose( SQLBASEAREAP pArea );
static HB_ERRCODE sddGoTo( SQLBASEAREAP pArea, HB_ULONG ulRecNo );
static HB_ERRCODE sddGetValue( SQLBASEAREAP pArea, HB_USHORT uiIndex, PHB_ITEM pItem );
static HB_ERRCODE sddGetVarLen( SQLBASEAREAP pArea, HB_USHORT uiIndex, HB_ULONG * pLength );


static const SDDNODE s_sddNull = {
   NULL,
   "NULL",
   ( SDDFUNC_CONNECT ) sddConnect,
   ( SDDFUNC_DISCONNECT ) sddDisconnect,
   ( SDDFUNC_EXECUTE ) sddExecute,
   ( SDDFUNC_OPEN ) sddOpen,
   ( SDDFUNC_CLOSE ) sddClose,
   ( SDDFUNC_GOTO ) sddGoTo,
   ( SDDFUNC_GETVALUE ) sddGetValue,
   ( SDDFUNC_GETVARLEN ) sddGetVarLen
};


static HB_ERRCODE sddConnect( SQLDDCONNECTION * pConnection, PHB_ITEM pItem )
{
   HB_SYMBOL_UNUSED( pConnection );
   HB_SYMBOL_UNUSED( pItem );
   hb_errRT_SQLBASE( EG_UNSUPPORTED, ESQLDD_NULLSDD, NULL, NULL );
   return HB_FAILURE;
}


static HB_ERRCODE sddDisconnect( SQLDDCONNECTION * pConnection )
{
   HB_SYMBOL_UNUSED( pConnection );
   hb_errRT_SQLBASE( EG_UNSUPPORTED, ESQLDD_NULLSDD, NULL, NULL );
   return HB_FAILURE;
}


static HB_ERRCODE sddExecute( SQLDDCONNECTION * pConnection, PHB_ITEM pItem )
{
   HB_SYMBOL_UNUSED( pConnection );
   HB_SYMBOL_UNUSED( pItem );
   hb_errRT_SQLBASE( EG_UNSUPPORTED, ESQLDD_NULLSDD, NULL, NULL );
   return HB_FAILURE;
}


static HB_ERRCODE sddOpen( SQLBASEAREAP pArea )
{
   HB_SYMBOL_UNUSED( pArea );
   hb_errRT_SQLBASE( EG_UNSUPPORTED, ESQLDD_NULLSDD, NULL, NULL );
   return HB_FAILURE;
}


static HB_ERRCODE sddClose( SQLBASEAREAP pArea )
{
   HB_SYMBOL_UNUSED( pArea );
   return HB_SUCCESS;
}


static HB_ERRCODE sddGoTo( SQLBASEAREAP pArea, HB_ULONG ulRecNo )
{
   if( ulRecNo == 0 || ulRecNo > pArea->ulRecCount )
   {
      pArea->pRecord      = pArea->pRow[ 0 ];
      pArea->bRecordFlags = pArea->pRowFlags[ 0 ];

      pArea->fPositioned = HB_FALSE;
   }
   else
   {
      pArea->pRecord      = pArea->pRow[ ulRecNo ];
      pArea->bRecordFlags = pArea->pRowFlags[ ulRecNo ];

      pArea->fPositioned = HB_TRUE;
   }
   return HB_SUCCESS;
}


static HB_ERRCODE sddGetValue( SQLBASEAREAP pArea, HB_USHORT uiIndex, PHB_ITEM pItem )
{
   HB_SYMBOL_UNUSED( pArea );
   HB_SYMBOL_UNUSED( uiIndex );
   HB_SYMBOL_UNUSED( pItem );
   hb_errRT_SQLBASE( EG_UNSUPPORTED, ESQLDD_NULLSDD, NULL, NULL );
   return HB_FAILURE;
}


static HB_ERRCODE sddGetVarLen( SQLBASEAREAP pArea, HB_USHORT uiIndex, HB_ULONG * pLength )
{
   HB_SYMBOL_UNUSED( pArea );
   HB_SYMBOL_UNUSED( uiIndex );
   HB_SYMBOL_UNUSED( pLength );
   hb_errRT_SQLBASE( EG_UNSUPPORTED, ESQLDD_NULLSDD, NULL, NULL );
   return HB_SUCCESS;
}


/* --- SDD registration --- */

static PSDDNODE s_pSdd = NULL;


int hb_sddRegister( PSDDNODE pSdd )
{
   PSDDNODE pNode = s_pSdd;

   /* "Inheritance" from NULL SDD */
   if( pSdd->Connect == NULL )
      pSdd->Connect = s_sddNull.Connect;
   if( pSdd->Disconnect == NULL )
      pSdd->Disconnect = s_sddNull.Disconnect;
   if( pSdd->Execute == NULL )
      pSdd->Execute = s_sddNull.Execute;
   if( pSdd->Open == NULL )
      pSdd->Open = s_sddNull.Open;
   if( pSdd->Close == NULL )
      pSdd->Close = s_sddNull.Close;
   if( pSdd->GoTo == NULL )
      pSdd->GoTo = s_sddNull.GoTo;
   if( pSdd->GetValue == NULL )
      pSdd->GetValue = s_sddNull.GetValue;
   if( pSdd->GetVarLen == NULL )
      pSdd->GetVarLen = s_sddNull.GetVarLen;

   while( pNode )
   {
      if( ! hb_stricmp( pNode->Name, pSdd->Name ) )
         return 0;
      pNode = pNode->pNext;
   }
   pSdd->pNext = s_pSdd;
   s_pSdd      = pSdd;
   return 1;
}


/* --- RDD METHODS --- */

static HB_ERRCODE sqlbaseGoBottom( SQLBASEAREAP pArea )
{
   if( SELF_GOCOLD( &pArea->area ) == HB_FAILURE )
      return HB_FAILURE;


   if( ! pArea->fFetched && pArea->pSDD->GoTo( pArea, ( HB_ULONG ) -1 ) == HB_FAILURE )
      return HB_FAILURE;

   pArea->area.fTop    = HB_FALSE;
   pArea->area.fBottom = HB_TRUE;

   if( SELF_GOTO( &pArea->area, pArea->ulRecCount ) != HB_SUCCESS )
      return HB_FAILURE;

   return SELF_SKIPFILTER( &pArea->area, -1 );
}


static HB_ERRCODE sqlbaseGoTo( SQLBASEAREAP pArea, HB_ULONG ulRecNo )
{
   if( SELF_GOCOLD( &pArea->area ) == HB_FAILURE )
      return HB_FAILURE;

   if( pArea->pSDD->GoTo( pArea, ulRecNo ) == HB_FAILURE )
      return HB_FAILURE;

   if( pArea->fPositioned )
   {
      pArea->ulRecNo   = ulRecNo;
      pArea->area.fBof = pArea->area.fEof = HB_FALSE;
   }
   else
   {
      pArea->ulRecNo   = pArea->ulRecCount + 1;
      pArea->area.fBof = pArea->area.fEof = HB_TRUE;
   }
   pArea->area.fFound = HB_FALSE;

   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseGoToId( SQLBASEAREAP pArea, PHB_ITEM pItem )
{
   if( HB_IS_NUMERIC( pItem ) )
      return SELF_GOTO( &pArea->area, hb_itemGetNL( pItem ) );
   else
   {
      PHB_ITEM pError = hb_errNew();
      hb_errPutGenCode( pError, EG_DATATYPE );
      hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATATYPE ) );
      hb_errPutSubCode( pError, EDBF_DATATYPE );
      SELF_ERROR( &pArea->area, pError );
      hb_itemRelease( pError );
      return HB_FAILURE;
   }
}


static HB_ERRCODE sqlbaseGoTop( SQLBASEAREAP pArea )
{
   pArea->area.fTop    = HB_TRUE;
   pArea->area.fBottom = HB_FALSE;

   if( SELF_GOTO( &pArea->area, 1 ) == HB_FAILURE )
      return HB_FAILURE;

   return SELF_SKIPFILTER( &pArea->area, 1 );
}


static HB_ERRCODE sqlbaseSkip( SQLBASEAREAP pArea, HB_LONG lToSkip )
{
   HB_ERRCODE errCode;

   if( pArea->lpdbPendingRel )
   {
      if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
         return HB_FAILURE;
   }

   pArea->area.fTop = pArea->area.fBottom = HB_FALSE;

   if( lToSkip == 0 || hb_setGetDeleted() ||
       pArea->area.dbfi.itmCobExpr || pArea->area.dbfi.fFilter )
      return SUPER_SKIP( &pArea->area, lToSkip );

   errCode = SELF_SKIPRAW( &pArea->area, lToSkip );

   /* Move first record and set Bof flag */
   if( errCode == HB_SUCCESS && pArea->area.fBof && lToSkip < 0 )
   {
      errCode = SELF_GOTOP( &pArea->area );
      pArea->area.fBof = HB_TRUE;
   }

   if( lToSkip < 0 )
      pArea->area.fEof = HB_FALSE;
   else /* if( lToSkip > 0 ) */
      pArea->area.fBof = HB_FALSE;

   return errCode;
}


static HB_ERRCODE sqlbaseSkipRaw( SQLBASEAREAP pArea, HB_LONG lToSkip )
{
   HB_ERRCODE errCode;

   if( pArea->lpdbPendingRel )
   {
      if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
         return HB_FAILURE;
   }

   if( lToSkip == 0 )
   {
      /* TODO: maybe gocold is enough here?! */
      HB_BOOL bBof, bEof;

      /* Save flags */
      bBof = pArea->area.fBof;
      bEof = pArea->area.fEof;

      errCode = SELF_GOTO( &pArea->area, pArea->ulRecNo );

      /* Restore flags */
      pArea->area.fBof = bBof;
      pArea->area.fEof = bEof;
   }
   else if( lToSkip < 0 && ( HB_ULONG ) ( -lToSkip ) >= pArea->ulRecNo )
   {
      errCode = SELF_GOTO( &pArea->area, 1 );
      pArea->area.fBof = HB_TRUE;
   }
   else
      errCode = SELF_GOTO( &pArea->area, pArea->ulRecNo + lToSkip );

   return errCode;
}


static HB_ERRCODE sqlbaseAppend( SQLBASEAREAP pArea, HB_BOOL bUnLockAll )
{
   HB_SYMBOL_UNUSED( bUnLockAll );

   /* This GOTO is GOCOLD + GOEOF */
   if( SELF_GOTO( &pArea->area, 0 ) == HB_FAILURE )
      return HB_FAILURE;

   if( ! pArea->fRecordChanged && SELF_GOHOT( &pArea->area ) == HB_FAILURE )
      return HB_FAILURE;

   if( pArea->ulRecCount + 1 >= pArea->ulRecMax )
   {
      pArea->pRow      = ( void ** ) hb_xrealloc( pArea->pRow, ( pArea->ulRecMax + SQLDD_ROWSET_RESIZE ) * sizeof( void * ) );
      pArea->pRowFlags = ( HB_BYTE * ) hb_xrealloc( pArea->pRowFlags, ( pArea->ulRecMax + SQLDD_ROWSET_RESIZE ) * sizeof( HB_BYTE ) );
      pArea->ulRecMax += SQLDD_ROWSET_RESIZE;
   }

   pArea->fAppend = pArea->fPositioned = HB_TRUE;
   pArea->ulRecCount++;
   pArea->ulRecNo   = pArea->ulRecCount;
   pArea->area.fBof = pArea->area.fEof = pArea->area.fFound = HB_FALSE;
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseDeleteRec( SQLBASEAREAP pArea )
{
   if( ! pArea->fPositioned )
      return HB_SUCCESS;

   if( ! pArea->fRecordChanged && SELF_GOHOT( &pArea->area ) == HB_FAILURE )
      return HB_FAILURE;

   pArea->bRecordFlags |= SQLDD_FLAG_DELETED;
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseDeleted( SQLBASEAREAP pArea, HB_BOOL * pDeleted )
{
   *pDeleted = pArea->bRecordFlags & SQLDD_FLAG_DELETED;
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseGetValue( SQLBASEAREAP pArea, HB_USHORT uiIndex, PHB_ITEM pItem )
{
   if( uiIndex == 0 || uiIndex > pArea->area.uiFieldCount )
      return HB_FAILURE;

   if( pArea->bRecordFlags & SQLDD_FLAG_CACHED )
   {
      hb_arrayGet( ( PHB_ITEM ) pArea->pRecord, uiIndex, pItem );
      return HB_SUCCESS;
   }
   return pArea->pSDD->GetValue( pArea, uiIndex, pItem );
}


static HB_ERRCODE sqlbaseGetVarLen( SQLBASEAREAP pArea, HB_USHORT uiIndex, HB_ULONG * pLength )
{
   /* TODO: should we use this code? */
#if 0
   if( pArea->area.lpFields[ uiIndex ].uiType == HB_IT_MEMO )
      return pArea->pSDD->GetVarLen( pArea, uiIndex, pLength );
#endif

   *pLength = pArea->area.lpFields[ uiIndex - 1 ].uiLen;
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseGoCold( SQLBASEAREAP pArea )
{
   if( pArea->fRecordChanged )
   {
      if( ! pArea->fAppend && pArea->pRowFlags[ pArea->ulRecNo ] & SQLDD_FLAG_CACHED )
         hb_itemRelease( ( PHB_ITEM ) ( pArea->pRow[ pArea->ulRecNo ] ) );
      pArea->pRow[ pArea->ulRecNo ]      = pArea->pRecord;
      pArea->pRowFlags[ pArea->ulRecNo ] = pArea->bRecordFlags;
      pArea->fRecordChanged = HB_FALSE;
      pArea->fAppend        = HB_FALSE;
   }
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseGoHot( SQLBASEAREAP pArea )
{
   PHB_ITEM  pArray, pItem;
   HB_USHORT us;

   pArray = hb_itemArrayNew( pArea->area.uiFieldCount );
   pItem = hb_itemNew( NULL );
   for( us = 1; us <= pArea->area.uiFieldCount; us++ )
   {
      if( SELF_GETVALUE( &pArea->area, us, pItem ) == HB_SUCCESS )
         hb_arraySetForward( pArray, us, pItem );
   }
   hb_itemRelease( pItem );
   pArea->pRecord        = pArray;
   pArea->bRecordFlags  |= SQLDD_FLAG_CACHED;
   pArea->fRecordChanged = HB_TRUE;
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbasePutValue( SQLBASEAREAP pArea, HB_USHORT uiIndex, PHB_ITEM pItem )
{
   LPFIELD    pField;
   HB_ERRCODE errCode;

   if( uiIndex == 0 || uiIndex > pArea->area.uiFieldCount )
      return HB_FAILURE;

   if( ! pArea->fPositioned )
      return HB_SUCCESS;

   if( ! pArea->fRecordChanged && SELF_GOHOT( &pArea->area ) == HB_FAILURE )
      return HB_FAILURE;

   errCode = HB_SUCCESS;
   pField  = pArea->area.lpFields + ( uiIndex - 1 );


   if( ( ( HB_IS_MEMO( pItem ) || HB_IS_STRING( pItem ) ) && ( pField->uiType == HB_FT_STRING || pField->uiType == HB_FT_MEMO ) ) ||
       ( HB_IS_DATE( pItem ) && pField->uiType == HB_FT_DATE ) ||
       ( HB_IS_TIMESTAMP( pItem ) && pField->uiType == HB_FT_TIMESTAMP ) ||
       ( HB_IS_NUMBER( pItem ) && ( pField->uiType == HB_FT_INTEGER || pField->uiType == HB_FT_LONG ||
                                    pField->uiType == HB_FT_FLOAT || pField->uiType == HB_FT_DOUBLE ) ) ||
       ( HB_IS_LOGICAL( pItem ) && pField->uiType == HB_FT_LOGICAL ) ||
       pField->uiType == HB_FT_ANY ||
       HB_IS_NIL( pItem ) )
   {
      hb_arraySet( ( PHB_ITEM ) pArea->pRecord, uiIndex, pItem );
   }
   else
   {
      PHB_ITEM pError;

      pError = hb_errNew();
      hb_errPutGenCode( pError, EG_DATATYPE );
      hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATATYPE ) );
      hb_errPutOperation( pError, hb_dynsymName( ( PHB_DYNS ) pField->sym ) );
      hb_errPutSubCode( pError, errCode );
      hb_errPutFlags( pError, EF_CANDEFAULT );
      errCode = SELF_ERROR( &pArea->area, pError );
      hb_itemRelease( pError );
      return errCode == E_DEFAULT ? HB_SUCCESS : HB_FAILURE;
   }
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseRecall( SQLBASEAREAP pArea )
{
   if( ! pArea->fPositioned )
      return HB_SUCCESS;

   if( ! pArea->fRecordChanged && SELF_GOHOT( &pArea->area ) != HB_SUCCESS )
      return HB_FAILURE;

   pArea->bRecordFlags &= ~SQLDD_FLAG_DELETED;
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseRecCount( SQLBASEAREAP pArea, HB_ULONG * pRecCount )
{
   *pRecCount = pArea->ulRecCount;
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseRecNo( SQLBASEAREAP pArea, HB_ULONG * ulRecNo )
{
   *ulRecNo = pArea->ulRecNo;
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseRecId( SQLBASEAREAP pArea, PHB_ITEM pRecNo )
{
   HB_ERRCODE errCode;
   HB_ULONG   ulRecNo;

   errCode = SELF_RECNO( &pArea->area, &ulRecNo );
   hb_itemPutNInt( pRecNo, ulRecNo );
   return errCode;
}


static HB_ERRCODE sqlbaseZap( SQLBASEAREAP pArea )
{
   HB_ULONG ulIndex;

   for( ulIndex = 1; ulIndex <= pArea->ulRecCount; ulIndex++ )
   {
      if( pArea->pRowFlags[ ulIndex ] & SQLDD_FLAG_CACHED )
         hb_itemRelease( ( PHB_ITEM ) pArea->pRow[ ulIndex ] );
   }

   pArea->ulRecCount = 0;
   pArea->ulRecNo = 0;

   pArea->pRow = ( void ** ) hb_xrealloc( pArea->pRow, SQLDD_ROWSET_RESIZE * sizeof( void * ) );
   pArea->pRowFlags = ( HB_BYTE * ) hb_xrealloc( pArea->pRowFlags, SQLDD_ROWSET_RESIZE * sizeof( HB_BYTE ) );
   pArea->ulRecMax = SQLDD_ROWSET_RESIZE;

   pArea->fFetched = HB_TRUE;

   pArea->fPositioned = HB_FALSE;

   return SELF_GOTOP( &pArea->area );
}


static HB_ERRCODE sqlbaseClose( SQLBASEAREAP pArea )
{
   if( SELF_GOCOLD( &pArea->area ) == HB_FAILURE )
      return HB_FAILURE;

   if( SUPER_CLOSE( &pArea->area ) == HB_FAILURE )
      return HB_FAILURE;

   if( pArea->pSDD )
      pArea->pSDD->Close( pArea );

   if( pArea->pRow )
   {
      HB_ULONG ulIndex;

      for( ulIndex = 0; ulIndex <= pArea->ulRecCount; ulIndex++ )
      {
         if( pArea->pRowFlags[ ulIndex ] & SQLDD_FLAG_CACHED )
            hb_itemRelease( ( PHB_ITEM ) pArea->pRow[ ulIndex ] );
      }
      hb_xfree( pArea->pRow );
      hb_xfree( pArea->pRowFlags );
      pArea->pRow      = NULL;
      pArea->pRowFlags = NULL;
   }

   if( pArea->szQuery )
   {
      hb_xfree( pArea->szQuery );
      pArea->szQuery = NULL;
   }
   if( pArea->pConnection )
   {
      /* It is possible to have areas without connection and SDD driver. Ex., arrayrdd. [Mindaugas] */
      pArea->pConnection->uiAreaCount--;
      pArea->pConnection = NULL;
   }
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseCreate( SQLBASEAREAP pArea, LPDBOPENINFO pOpenInfo )
{
   PHB_ITEM  pItemEof, pItem;
   HB_USHORT uiCount;
   HB_BOOL   bError;

   pArea->ulConnection = pOpenInfo->ulConnection ? pOpenInfo->ulConnection : s_ulConnectionCurrent;

   if( pArea->ulConnection > s_ulConnectionCount ||
       ( pArea->ulConnection && ! s_pConnection[ pArea->ulConnection - 1 ] ) )
   {
      hb_errRT_SQLBASE( EG_OPEN, ESQLDD_NOTCONNECTED, "Not connected", NULL );
      return HB_FAILURE;
   }

   if( pArea->ulConnection )
   {
      pArea->pConnection = s_pConnection[ pArea->ulConnection - 1 ];
      pArea->pConnection->uiAreaCount++;
      pArea->pSDD = pArea->pConnection->pSDD;
   }
   else
      pArea->pSDD = &s_sddNull;

   pItemEof = hb_itemArrayNew( pArea->area.uiFieldCount );

   bError = HB_FALSE;
   for( uiCount = 0; uiCount < pArea->area.uiFieldCount; uiCount++ )
   {
      LPFIELD pField = pArea->area.lpFields + uiCount;

      switch( pField->uiType )
      {
         case HB_FT_STRING:
         {
            char * pStr;

            pStr = ( char * ) hb_xgrab( pField->uiLen + 1 );
            memset( pStr, ' ', pField->uiLen );
            pStr[ pField->uiLen ] = '\0';

            pItem = hb_itemPutCL( NULL, pStr, pField->uiLen );
            hb_xfree( pStr );
            break;
         }

         case HB_FT_MEMO:
            pItem = hb_itemPutC( NULL, NULL );
            break;

         case HB_FT_INTEGER:
            if( pField->uiDec )
               pItem = hb_itemPutND( NULL, 0.0 );
            else
               pItem = hb_itemPutNI( NULL, 0 );
            break;

         case HB_FT_LONG:
            if( pField->uiDec )
               pItem = hb_itemPutND( NULL, 0.0 );
            else
               pItem = hb_itemPutNL( NULL, 0 );
            break;

         case HB_FT_FLOAT:
            pItem = hb_itemPutND( NULL, 0.0 );
            break;

         case HB_FT_DOUBLE:
            pItem = hb_itemPutND( NULL, 0.0 );
            break;

         case HB_FT_DATE:
            pItem = hb_itemPutDS( NULL, NULL );
            break;

         case HB_FT_TIMESTAMP:
            pItem = hb_itemPutTDT( NULL, 0, 0 );
            break;

         case HB_FT_LOGICAL:
            pItem = hb_itemPutL( NULL, HB_FALSE );
            break;

         default:
            pItem  = hb_itemNew( NULL );
            bError = HB_TRUE;
            break;
      }

      hb_arraySetForward( pItemEof, uiCount + 1, pItem );
      hb_itemRelease( pItem );

      if( bError )
         break;
   }

   if( bError )
   {
      hb_itemClear( pItemEof );
      hb_itemRelease( pItemEof );
      hb_errRT_SQLBASE( EG_CORRUPTION, ESQLDD_INVALIDFIELD, "Invalid field type", NULL );
      SELF_CLOSE( &pArea->area );
      return HB_FAILURE;
   }

   pArea->ulRecCount = 0;

   pArea->pRow      = ( void ** ) hb_xgrab( SQLDD_ROWSET_RESIZE * sizeof( void * ) );
   pArea->pRowFlags = ( HB_BYTE * ) hb_xgrab( SQLDD_ROWSET_RESIZE * sizeof( HB_BYTE ) );
   pArea->ulRecMax  = SQLDD_ROWSET_RESIZE;

   pArea->pRow[ 0 ]      = pItemEof;
   pArea->pRowFlags[ 0 ] = SQLDD_FLAG_CACHED;
   pArea->fFetched       = HB_TRUE;

   if( SUPER_CREATE( &pArea->area, pOpenInfo ) != HB_SUCCESS )
   {
      SELF_CLOSE( &pArea->area );
      return HB_FAILURE;
   }

   return SELF_GOTOP( &pArea->area );
}


static HB_ERRCODE sqlbaseInfo( SQLBASEAREAP pArea, HB_USHORT uiIndex, PHB_ITEM pItem )
{
   switch( uiIndex )
   {
      case DBI_QUERY:
         hb_itemPutC( pItem, pArea->szQuery );
         break;

      default:
         return SUPER_INFO( &pArea->area, uiIndex, pItem );
   }

   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseOpen( SQLBASEAREAP pArea, LPDBOPENINFO pOpenInfo )
{
   HB_ERRCODE errCode;

   pArea->ulConnection = pOpenInfo->ulConnection ? pOpenInfo->ulConnection : s_ulConnectionCurrent;

   if( pArea->ulConnection == 0 || pArea->ulConnection > s_ulConnectionCount ||
       ! s_pConnection[ pArea->ulConnection - 1 ] )
   {
      hb_errRT_SQLBASE( EG_OPEN, ESQLDD_NOTCONNECTED, "Not connected", NULL );
      return HB_FAILURE;
   }

   if( pArea->area.uiFieldCount )
      /* This should not happen (in __dbTrans()), because RDD is registered with RDT_FULL */
      return HB_FAILURE;

   pArea->pConnection = s_pConnection[ pArea->ulConnection - 1 ];
   pArea->pConnection->uiAreaCount++;
   pArea->pSDD = pArea->pConnection->pSDD;

   /* filename is a query */
   pArea->szQuery = hb_strdup( pOpenInfo->abName );

   errCode = pArea->pSDD->Open( pArea );

   if( errCode == HB_SUCCESS )
      errCode = SUPER_OPEN( &pArea->area, pOpenInfo );

   if( errCode != HB_SUCCESS )
   {
      SELF_CLOSE( &pArea->area );
      return HB_FAILURE;
   }
   return SELF_GOTOP( &pArea->area );
}


static HB_ERRCODE sqlbaseStructSize( SQLBASEAREAP pArea, HB_USHORT * uiSize )
{
   HB_SYMBOL_UNUSED( pArea );

   *uiSize = sizeof( SQLBASEAREA );
   return HB_SUCCESS;
}


#if 0
static HB_ERRCODE sqlbaseChildEnd( SQLBASEAREAP pArea, LPDBRELINFO pRelInfo )
{
   HB_ERRCODE errCode;

   if( pArea->lpdbPendingRel == pRelInfo )
      errCode = SELF_FORCEREL( &pArea->area );
   else
      errCode = HB_SUCCESS;
   SUPER_CHILDEND( &pArea->area, pRelInfo );
   return errCode;
}


static HB_ERRCODE sqlbaseChildStart( SQLBASEAREAP pArea, LPDBRELINFO pRelInfo )
{
   if( SELF_CHILDSYNC( &pArea->area, pRelInfo ) != HB_SUCCESS )
      return HB_FAILURE;
   return SUPER_CHILDSTART( &pArea->area, pRelInfo );
}


static HB_ERRCODE sqlbaseChildSync( SQLBASEAREAP pArea, LPDBRELINFO pRelInfo )
{
   if( SELF_GOCOLD( &pArea->area ) != HB_SUCCESS )
      return HB_FAILURE;

   pArea->lpdbPendingRel = pRelInfo;

   if( pArea->lpdbRelations )
      return SELF_SYNCCHILDREN( &pArea->area );

   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseForceRel( SQLBASEAREAP pArea )
{
   if( pArea->lpdbPendingRel )
   {
      LPDBRELINFO lpdbPendingRel;

      lpdbPendingRel        = pArea->lpdbPendingRel;
      pArea->lpdbPendingRel = NULL;
      return SELF_RELEVAL( &pArea->area, lpdbPendingRel );
   }
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseSetFilter( SQLBASEAREAP pArea, LPDBFILTERINFO pFilterInfo )
{
   if( pArea->lpdbPendingRel )
   {
      if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
         return HB_FAILURE;
   }
   return SUPER_SETFILTER( &pArea->area, pFilterInfo );
}
#endif


static HB_ERRCODE sqlbaseInit( LPRDDNODE pRDD )
{
   HB_SYMBOL_UNUSED( pRDD );

   s_pItemNewID = hb_itemNew( NULL );
   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseExit( LPRDDNODE pRDD )
{
   HB_SYMBOL_UNUSED( pRDD );

   if( s_pConnection )
   {
      HB_ULONG ul;

      /* Disconnect all connections */
      for( ul = 0; ul < s_ulConnectionCount; ul++ )
      {
         if( s_pConnection[ ul ] )
         {
            s_pConnection[ ul ]->pSDD->Disconnect( s_pConnection[ ul ] );
            hb_xfree( s_pConnection[ ul ] );
         }
      }
      hb_xfree( s_pConnection );
      s_pConnection         = NULL;
      s_ulConnectionCount   = 0;
      s_ulConnectionCurrent = 0;
      if( s_szError )
      {
         hb_xfree( s_szError );
         s_szError = NULL;
      }
      if( s_szQuery )
      {
         hb_xfree( s_szQuery );
         s_szQuery = NULL;
      }
      hb_itemRelease( s_pItemNewID );
      s_pItemNewID = NULL;
   }

   return HB_SUCCESS;
}


static HB_ERRCODE sqlbaseRddInfo( LPRDDNODE pRDD, HB_USHORT uiIndex, HB_ULONG ulConnect, PHB_ITEM pItem )
{
   HB_ULONG ulConn;
   SQLDDCONNECTION * pConn;

   HB_SYMBOL_UNUSED( pRDD );

   ulConn = ulConnect ? ulConnect : s_ulConnectionCurrent;
   if( ulConn > 0 && ulConn <= s_ulConnectionCount )
      pConn = s_pConnection[ ulConn - 1 ];
   else
      pConn = NULL;

   switch( uiIndex )
   {
      case RDDI_REMOTE:
         hb_itemPutL( pItem, HB_TRUE );
         break;

      case RDDI_CONNECTION:
      {
         HB_ULONG ulNewConnection = 0;

         if( hb_itemType( pItem ) & HB_IT_NUMERIC )
            ulNewConnection = hb_itemGetNL( pItem );

         hb_itemPutNL( pItem, ulConnect ? ulConnect : s_ulConnectionCurrent );

         if( ulNewConnection )
            s_ulConnectionCurrent = ulNewConnection;
         break;
      }

      case RDDI_ISDBF:
         hb_itemPutL( pItem, HB_FALSE );
         break;

      case RDDI_CANPUTREC:
         hb_itemPutL( pItem, HB_TRUE );
         break;

      case RDDI_CONNECT:
      {
         PSDDNODE     pNode = NULL;
         HB_ULONG     ul;
         const char * pStr;

         pStr = hb_arrayGetCPtr( pItem, 1 );
         if( pStr )
         {
            pNode = s_pSdd;
            while( pNode )
            {
               if( ! hb_stricmp( pNode->Name, pStr ) )
                  break;
               pNode = pNode->pNext;
            }
         }

         hb_rddsqlSetError( 0, NULL, NULL, NULL, 0 );
         pConn = ( SQLDDCONNECTION * ) hb_xgrabz( sizeof( SQLDDCONNECTION ) );
         if( pNode && pNode->Connect( pConn, pItem ) == HB_SUCCESS )
         {
            pConn->pSDD = pNode;

            /* Find free connection handle */
            for( ul = 0; ul < s_ulConnectionCount; ul++ )
            {
               if( ! s_pConnection[ ul ] )
                  break;
            }
            if( ul >= s_ulConnectionCount )
            {
               /* Realloc connection table */
               if( s_pConnection )
                  s_pConnection = ( SQLDDCONNECTION ** ) hb_xrealloc( s_pConnection, sizeof( SQLDDCONNECTION * ) * ( s_ulConnectionCount + CONNECTION_LIST_EXPAND ) );
               else
                  s_pConnection = ( SQLDDCONNECTION ** ) hb_xgrab( sizeof( SQLDDCONNECTION * ) * CONNECTION_LIST_EXPAND );

               memset( s_pConnection + s_ulConnectionCount, 0, sizeof( SQLDDCONNECTION * ) * CONNECTION_LIST_EXPAND );
               ul = s_ulConnectionCount;
               s_ulConnectionCount += CONNECTION_LIST_EXPAND;
            }
            s_pConnection[ ul ] = pConn;
            ul++;
            s_ulConnectionCurrent = ul;
         }
         else
         {
            hb_xfree( pConn );
            ul = 0;
         }

         hb_itemPutNI( pItem, ul );
         break;
      }

      case RDDI_DISCONNECT:
         hb_rddsqlSetError( 0, NULL, NULL, NULL, 0 );
         if( pConn && ! pConn->uiAreaCount && pConn->pSDD->Disconnect( pConn ) == HB_SUCCESS )
         {
            hb_xfree( pConn );
            s_pConnection[ ulConn - 1 ] = NULL;
            if( s_ulConnectionCurrent == ulConn )
               s_ulConnectionCurrent = 0;

            hb_itemPutL( pItem, HB_TRUE );
            return HB_SUCCESS;
         }
         hb_itemPutL( pItem, HB_FALSE );
         return HB_SUCCESS;

      case RDDI_EXECUTE:
         hb_rddsqlSetError( 0, NULL, NULL, NULL, 0 );
         if( pConn )
            hb_itemPutL( pItem, pConn->pSDD->Execute( pConn, pItem ) == HB_SUCCESS );
         else
            hb_itemPutL( pItem, HB_FALSE );

         return HB_SUCCESS;

      case RDDI_ERROR:
         hb_itemPutC( pItem, s_szError );
         return HB_SUCCESS;

      case RDDI_ERRORNO:
         hb_itemPutNI( pItem, s_errCode );
         return HB_SUCCESS;

      case RDDI_QUERY:
         hb_itemPutC( pItem, s_szQuery );
         return HB_SUCCESS;

      case RDDI_INSERTID:
         hb_itemCopy( pItem, s_pItemNewID );
         return HB_SUCCESS;

      case RDDI_AFFECTEDROWS:
         hb_itemPutNInt( pItem, s_ulAffectedRows );
         return HB_SUCCESS;

#if 0
      default:
         return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem );
#endif

   }

   return HB_SUCCESS;
}


/* --- */

static RDDFUNCS sqlbaseTable =
{
   ( DBENTRYP_BP ) NULL,             /* sqlbaseBof */
   ( DBENTRYP_BP ) NULL,             /* sqlbaseEof */
   ( DBENTRYP_BP ) NULL,             /* sqlbaseFound */
   ( DBENTRYP_V ) sqlbaseGoBottom,
   ( DBENTRYP_UL ) sqlbaseGoTo,
   ( DBENTRYP_I ) sqlbaseGoToId,
   ( DBENTRYP_V ) sqlbaseGoTop,
   ( DBENTRYP_BIB ) NULL,            /* sqlbaseSeek */
   ( DBENTRYP_L ) sqlbaseSkip,
   ( DBENTRYP_L ) NULL,              /* sqlbaseSkipFilter */
   ( DBENTRYP_L ) sqlbaseSkipRaw,
   ( DBENTRYP_VF ) NULL,             /* sqlbaseAddField */
   ( DBENTRYP_B ) sqlbaseAppend,
   ( DBENTRYP_I ) NULL,              /* sqlbaseCreateFields */
   ( DBENTRYP_V ) sqlbaseDeleteRec,
   ( DBENTRYP_BP ) sqlbaseDeleted,
   ( DBENTRYP_SP ) NULL,             /* sqlbaseFieldCount */
   ( DBENTRYP_VF ) NULL,             /* sqlbaseFieldDisplay */
   ( DBENTRYP_SSI ) NULL,            /* sqlbaseFieldInfo */
   ( DBENTRYP_SCP ) NULL,            /* sqlbaseFieldName */
   ( DBENTRYP_V ) NULL,              /* sqlbaseFlush */
   ( DBENTRYP_PP ) NULL,             /* sqlbaseGetRec */
   ( DBENTRYP_SI ) sqlbaseGetValue,
   ( DBENTRYP_SVL ) sqlbaseGetVarLen,
   ( DBENTRYP_V ) sqlbaseGoCold,
   ( DBENTRYP_V ) sqlbaseGoHot,
   ( DBENTRYP_P ) NULL,              /* sqlbasePutRec */
   ( DBENTRYP_SI ) sqlbasePutValue,
   ( DBENTRYP_V ) sqlbaseRecall,
   ( DBENTRYP_ULP ) sqlbaseRecCount,
   ( DBENTRYP_ISI ) NULL,            /* sqlbaseRecInfo */
   ( DBENTRYP_ULP ) sqlbaseRecNo,
   ( DBENTRYP_I ) sqlbaseRecId,
   ( DBENTRYP_S ) NULL,              /* sqlbaseSetFieldExtent */
   ( DBENTRYP_CP ) NULL,             /* sqlbaseAlias */
   ( DBENTRYP_V ) sqlbaseClose,
   ( DBENTRYP_VO ) sqlbaseCreate,
   ( DBENTRYP_SI ) sqlbaseInfo,
   ( DBENTRYP_V ) NULL,              /* sqlbaseNewArea */
   ( DBENTRYP_VO ) sqlbaseOpen,
   ( DBENTRYP_V ) NULL,              /* sqlbaseRelease */
   ( DBENTRYP_SP ) sqlbaseStructSize,
   ( DBENTRYP_CP ) NULL,             /* sqlbaseSysName */
   ( DBENTRYP_VEI ) NULL,            /* sqlbaseEval */
   ( DBENTRYP_V ) NULL,              /* sqlbasePack */
   ( DBENTRYP_LSP ) NULL,            /* sqlbasePackRec */
   ( DBENTRYP_VS ) NULL,             /* sqlbaseSort */
   ( DBENTRYP_VT ) NULL,             /* sqlbaseTrans */
   ( DBENTRYP_VT ) NULL,             /* sqlbaseTransRec */
   ( DBENTRYP_V ) sqlbaseZap,
   ( DBENTRYP_VR ) NULL,             /* sqlbaseChildEnd */
   ( DBENTRYP_VR ) NULL,             /* sqlbaseChildStart */
   ( DBENTRYP_VR ) NULL,             /* sqlbaseChildSync */
   ( DBENTRYP_V ) NULL,              /* sqlbaseSyncChildren */
   ( DBENTRYP_V ) NULL,              /* sqlbaseClearRel */
   ( DBENTRYP_V ) NULL,              /* sqlbaseForceRel */
   ( DBENTRYP_SSP ) NULL,            /* sqlbaseRelArea */
   ( DBENTRYP_VR ) NULL,             /* sqlbaseRelEval */
   ( DBENTRYP_SI ) NULL,             /* sqlbaseRelText */
   ( DBENTRYP_VR ) NULL,             /* sqlbaseSetRel */
   ( DBENTRYP_VOI ) NULL,            /* sqlbaseOrderListAdd */
   ( DBENTRYP_V ) NULL,              /* sqlbaseOrderListClear */
   ( DBENTRYP_VOI ) NULL,            /* sqlbaseOrderListDelete */
   ( DBENTRYP_VOI ) NULL,            /* sqlbaseOrderListFocus */
   ( DBENTRYP_V ) NULL,              /* sqlbaseOrderListRebuild */
   ( DBENTRYP_VOO ) NULL,            /* sqlbaseOrderCondition */
   ( DBENTRYP_VOC ) NULL,            /* sqlbaseOrderCreate */
   ( DBENTRYP_VOI ) NULL,            /* sqlbaseOrderDestroy */
   ( DBENTRYP_SVOI ) NULL,           /* sqlbaseOrderInfo */
   ( DBENTRYP_V ) NULL,              /* sqlbaseClearFilter */
   ( DBENTRYP_V ) NULL,              /* sqlbaseClearLocate */
   ( DBENTRYP_V ) NULL,              /* sqlbaseClearScope */
   ( DBENTRYP_VPLP ) NULL,           /* sqlbaseCountScope */
   ( DBENTRYP_I ) NULL,              /* sqlbaseFilterText */
   ( DBENTRYP_SI ) NULL,             /* sqlbaseScopeInfo */
   ( DBENTRYP_VFI ) NULL,            /* sqlbaseSetFilter */
   ( DBENTRYP_VLO ) NULL,            /* sqlbaseSetLocate */
   ( DBENTRYP_VOS ) NULL,            /* sqlbaseSetScope */
   ( DBENTRYP_VPL ) NULL,            /* sqlbaseSkipScope */
   ( DBENTRYP_B ) NULL,              /* sqlbaseLocate */
   ( DBENTRYP_CC ) NULL,             /* sqlbaseCompile */
   ( DBENTRYP_I ) NULL,              /* sqlbaseError */
   ( DBENTRYP_I ) NULL,              /* sqlbaseEvalBlock */
   ( DBENTRYP_VSP ) NULL,            /* sqlbaseRawLock */
   ( DBENTRYP_VL ) NULL,             /* sqlbaseLock */
   ( DBENTRYP_I ) NULL,              /* sqlbaseUnLock */
   ( DBENTRYP_V ) NULL,              /* sqlbaseCloseMemFile */
   ( DBENTRYP_VO ) NULL,             /* sqlbaseCreateMemFile */
   ( DBENTRYP_SCCS ) NULL,           /* sqlbaseGetValueFile */
   ( DBENTRYP_VO ) NULL,             /* sqlbaseOpenMemFile */
   ( DBENTRYP_SCCS ) NULL,           /* sqlbasePutValueFile */
   ( DBENTRYP_V ) NULL,              /* sqlbaseReadDBHeader */
   ( DBENTRYP_V ) NULL,              /* sqlbaseWriteDBHeader */
   ( DBENTRYP_R ) sqlbaseInit,
   ( DBENTRYP_R ) sqlbaseExit,
   ( DBENTRYP_RVVL ) NULL,           /* sqlbaseDrop */
   ( DBENTRYP_RVVL ) NULL,           /* sqlbaseExists */
   ( DBENTRYP_RVVVL ) NULL,          /* sqlbaseRename */
   ( DBENTRYP_RSLV ) sqlbaseRddInfo,
   ( DBENTRYP_SVP ) NULL             /* sqlbaseWhoCares */
};


/* --- Module initialization code --- */

HB_FUNC( SQLBASE )
{
}

HB_FUNC_STATIC( SQLBASE_GETFUNCTABLE )
{
   RDDFUNCS *  pTable;
   HB_USHORT * puiCount, uiRddId;

   puiCount = ( HB_USHORT * ) hb_parptr( 1 );
   pTable   = ( RDDFUNCS * ) hb_parptr( 2 );
   uiRddId  = ( HB_USHORT ) hb_parni( 4 );

   if( pTable )
   {
      HB_ERRCODE errCode;

      if( puiCount )
         *puiCount = RDDFUNCSCOUNT;

      errCode = hb_rddInheritEx( pTable, &sqlbaseTable, &sqlbaseSuper, NULL, NULL );
      if( errCode == HB_SUCCESS )
         s_rddidSQLBASE = uiRddId;

      hb_retni( errCode );
   }
   else
      hb_retni( HB_FAILURE );
}

static void hb_sqlbaseInit( void * cargo )
{
   HB_SYMBOL_UNUSED( cargo );

   if( hb_rddRegister( "SQLBASE", RDT_FULL ) > 1 )
      hb_errInternal( HB_EI_RDDINVALID, NULL, NULL, NULL );
}

HB_INIT_SYMBOLS_BEGIN( sqlbase__InitSymbols )
{
   "SQLBASE", { HB_FS_PUBLIC }, { HB_FUNCNAME( SQLBASE ) }, NULL
},
{ "SQLBASE_GETFUNCTABLE", { HB_FS_PUBLIC }, { HB_FUNCNAME( SQLBASE_GETFUNCTABLE ) }, NULL }
HB_INIT_SYMBOLS_END( sqlbase__InitSymbols )

HB_CALL_ON_STARTUP_BEGIN( _hb_sqlbase_init_ )
hb_vmAtInit( hb_sqlbaseInit, NULL );
HB_CALL_ON_STARTUP_END( _hb_sqlbase_init_ )

#if defined( HB_PRAGMA_STARTUP )
   #pragma startup sqlbase__InitSymbols
   #pragma startup _hb_sqlbase_init_
#elif defined( HB_DATASEG_STARTUP )
   #define HB_DATASEG_BODY  HB_DATASEG_FUNC( sqlbase__InitSymbols ) \
   HB_DATASEG_FUNC( _hb_sqlbase_init_ )
   #include "hbiniseg.h"
#endif
