From ad8389d113ccb1ec9003c3669d6c7ffecd36ea22 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 21 Oct 2008 06:43:47 +0000 Subject: [PATCH] 2008-10-21 08:29 UTC+0200 Viktor Szakats (harbour.01 syenar hu) + contrib/rddsql + contrib/rddsql/common.mak + contrib/rddsql/tests + contrib/rddsql/tests/test1.prg + contrib/rddsql/tests/bld_b32.bat + contrib/rddsql/tests/bld_vc.bat + contrib/rddsql/Makefile + contrib/rddsql/make_b32.bat + contrib/rddsql/make_vc.bat + contrib/rddsql/make_gcc.sh + contrib/rddsql/mysqldd.c + contrib/rddsql/sqlbase.c + contrib/rddsql/sqlmix.c + contrib/rddsql/hbsqldd.h + Added SQL RDD sent to the list by Mindaugas. * Changed strcpy(), unused vars, startup code, added make files, fixed all MSVS/BCC warnings, other minor cleanups. * Changed 'BYTE val[]' to 'BYTE * val' in struct decl. ; TOFIX: It doesn't compile on MSVC due to this error: .\mysqldd.c(65) : fatal error C1017: invalid integer constant expression * ChangeLog + Marked one change as TOMERGE. * contrib/hbdbgfx/dbgfxc.c * Minor cleanup. * source/vm/harbinit.prg * Minor. * source/rtl/xhelp.c ! Typo in comment. * source/rtl/valtoexp.prg * source/rtl/alert.prg * {|| ... } -> {||...} for consistency along Harbour. --- harbour/ChangeLog | 40 + harbour/contrib/hbdbgfx/dbgfxc.c | 4 +- harbour/contrib/rddsql/Makefile | 28 + harbour/contrib/rddsql/common.mak | 15 + harbour/contrib/rddsql/hbsqldd.h | 352 ++++ harbour/contrib/rddsql/make_b32.bat | 69 + harbour/contrib/rddsql/make_gcc.sh | 24 + harbour/contrib/rddsql/make_vc.bat | 70 + harbour/contrib/rddsql/mysqldd.c | 603 ++++++ harbour/contrib/rddsql/sqlbase.c | 1154 +++++++++++ harbour/contrib/rddsql/sqlmix.c | 2350 ++++++++++++++++++++++ harbour/contrib/rddsql/tests/bld_b32.bat | 14 + harbour/contrib/rddsql/tests/bld_vc.bat | 14 + harbour/contrib/rddsql/tests/test1.prg | 56 + harbour/source/rtl/alert.prg | 2 +- harbour/source/rtl/valtoexp.prg | 2 +- harbour/source/rtl/xhelp.c | 4 +- harbour/source/vm/harbinit.prg | 4 +- 18 files changed, 4797 insertions(+), 8 deletions(-) create mode 100644 harbour/contrib/rddsql/Makefile create mode 100644 harbour/contrib/rddsql/common.mak create mode 100644 harbour/contrib/rddsql/hbsqldd.h create mode 100644 harbour/contrib/rddsql/make_b32.bat create mode 100755 harbour/contrib/rddsql/make_gcc.sh create mode 100644 harbour/contrib/rddsql/make_vc.bat create mode 100644 harbour/contrib/rddsql/mysqldd.c create mode 100644 harbour/contrib/rddsql/sqlbase.c create mode 100644 harbour/contrib/rddsql/sqlmix.c create mode 100644 harbour/contrib/rddsql/tests/bld_b32.bat create mode 100644 harbour/contrib/rddsql/tests/bld_vc.bat create mode 100644 harbour/contrib/rddsql/tests/test1.prg diff --git a/harbour/ChangeLog b/harbour/ChangeLog index e0d0f1a4b0..1ce2254f7a 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,45 @@ 2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org) */ +2008-10-21 08:29 UTC+0200 Viktor Szakats (harbour.01 syenar hu) + + contrib/rddsql + + contrib/rddsql/common.mak + + contrib/rddsql/tests + + contrib/rddsql/tests/test1.prg + + contrib/rddsql/tests/bld_b32.bat + + contrib/rddsql/tests/bld_vc.bat + + contrib/rddsql/Makefile + + contrib/rddsql/make_b32.bat + + contrib/rddsql/make_vc.bat + + contrib/rddsql/make_gcc.sh + + contrib/rddsql/mysqldd.c + + contrib/rddsql/sqlbase.c + + contrib/rddsql/sqlmix.c + + contrib/rddsql/hbsqldd.h + + Added SQL RDD sent to the list by Mindaugas. + * Changed strcpy(), unused vars, startup code, + added make files, fixed all MSVS/BCC warnings, + other minor cleanups. + * Changed 'BYTE val[]' to 'BYTE * val' in struct decl. + ; TOFIX: It doesn't compile on MSVC due to this error: + .\mysqldd.c(65) : fatal error C1017: invalid integer constant expression + + * ChangeLog + + Marked one change as TOMERGE. + + * contrib/hbdbgfx/dbgfxc.c + * Minor cleanup. + + * source/vm/harbinit.prg + * Minor. + + * source/rtl/xhelp.c + ! Typo in comment. + + * source/rtl/valtoexp.prg + * source/rtl/alert.prg + * {|| ... } -> {||...} for consistency along Harbour. + 2008-10-21 02:40 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/common.mak * harbour/source/lang/Makefile @@ -66,6 +105,7 @@ 2008-10-20 01:18 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/include/hbstack.h ! added HB_EXPORT to hb_stack*() functions used in -gc3 code + [TOMERGE 1.0] 2008-10-20 00:25 UTC+0200 Francesco Saverio Giudice (info fsgiudice com) * contrib/hbdbgfx diff --git a/harbour/contrib/hbdbgfx/dbgfxc.c b/harbour/contrib/hbdbgfx/dbgfxc.c index 35bcd9a212..9f369df48b 100644 --- a/harbour/contrib/hbdbgfx/dbgfxc.c +++ b/harbour/contrib/hbdbgfx/dbgfxc.c @@ -103,10 +103,10 @@ HB_EXPORT BOOL hb_EmptyLogFile( BOOL bOnOff ) HB_EXPORT void hb_ToLogFile( const char * sFile, const char * sTraceMsg, ... ) { - FILE * hFile; - if( s_bToLogFile ) { + FILE * hFile; + if( sFile == NULL ) { if( s_bEmptyLogFile ) diff --git a/harbour/contrib/rddsql/Makefile b/harbour/contrib/rddsql/Makefile new file mode 100644 index 0000000000..e402f4366d --- /dev/null +++ b/harbour/contrib/rddsql/Makefile @@ -0,0 +1,28 @@ +# +# $Id$ +# + +ROOT = ../../ + +LIBNAME=rddsql + +ifeq ($(HB_INC_MYSQL),) +ifeq ($(HB_XBUILD),) +HB_INC_MYSQL = /usr/include/mysql +endif +endif + +HB_INC_MYSQL_OK += $(foreach d, $(HB_INC_MYSQL), $(if $(wildcard $(d)/mysql.h),$(d),)) + +ifneq ($(strip $(HB_INC_MYSQL_OK)),) + +C_USR += $(foreach d, $(HB_INC_MYSQL_OK), -I$(d)) + +C_SOURCES=\ + mysqldd.c \ + sqlbase.c \ + sqlmix.c \ + +else +include $(TOP)$(ROOT)config/none.cf +endif diff --git a/harbour/contrib/rddsql/common.mak b/harbour/contrib/rddsql/common.mak new file mode 100644 index 0000000000..afe905fb68 --- /dev/null +++ b/harbour/contrib/rddsql/common.mak @@ -0,0 +1,15 @@ +# +# $Id$ +# + +LIBNAME = $(LIBPREF)rddsql + +LIB_PATH = $(LIB_DIR)$(LIBNAME)$(LIBEXT) + +LIB_OBJS = \ + $(OBJ_DIR)mysqldd$(OBJEXT) \ + $(OBJ_DIR)sqlbase$(OBJEXT) \ + $(OBJ_DIR)sqlmix$(OBJEXT) \ + +all: \ + $(LIB_PATH) \ diff --git a/harbour/contrib/rddsql/hbsqldd.h b/harbour/contrib/rddsql/hbsqldd.h new file mode 100644 index 0000000000..cc58206f7f --- /dev/null +++ b/harbour/contrib/rddsql/hbsqldd.h @@ -0,0 +1,352 @@ +/* + * $Id$ + */ + +/* + * SQL Database Driver include file + * + * Copyright 2007 Mindaugas Kavaliauskas + * 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. + * + */ + + +#ifndef HBSQLDD_H_ +#define HBSQLDD_H_ + +#include "hbapirdd.h" +#include "hbdbferr.h" +#include "hbapierr.h" +#include "hbapilng.h" +#include "hbapi.h" + + +// New ...INFO_ constants +#define DBI_QUERY 1001 + +#define RDDI_CONNECT 1001 +#define RDDI_DISCONNECT 1002 +#define RDDI_EXECUTE 1003 +#define RDDI_ERROR 1004 +#define RDDI_ERRORNO 1005 +#define RDDI_NEWID 1006 +#define RDDI_AFFECTEDROWS 1007 +#define RDDI_QUERY 1008 + + +//==================================================================== +// SQLBASE +//==================================================================== + +#define MAX_FIELD_NAME 64 + +#define SQLDD_ROWSET_INIT 256 +#define SQLDD_ROWSET_RESIZE 64 + +#define SQLDD_FLAG_DELETED 1 +#define SQLDD_FLAG_CACHED 2 + + +typedef struct _SQLBASEAREA +{ + struct _RDDFUNCS * lprfsHost; /* Virtual method table for this workarea */ + USHORT uiArea; /* The number assigned to this workarea */ + void * atomAlias; /* Pointer to the alias symbol for this workarea */ + USHORT uiFieldExtent; /* Total number of fields allocated */ + USHORT uiFieldCount; /* Total number of fields used */ + LPFIELD lpFields; /* Pointer to an array of fields */ + void * lpFieldExtents; /* Void ptr for additional field properties */ + PHB_ITEM valResult; /* All purpose result holder */ + BOOL fTop; /* TRUE if "top" */ + BOOL fBottom; /* TRUE if "bottom" */ + BOOL fBof; /* TRUE if "bof" */ + BOOL fEof; /* TRUE if "eof" */ + BOOL fFound; /* TRUE if "found" */ + DBSCOPEINFO dbsi; /* Info regarding last LOCATE */ + DBFILTERINFO dbfi; /* Filter in effect */ + LPDBORDERCONDINFO lpdbOrdCondInfo; + LPDBRELINFO lpdbRelations; /* Parent/Child relationships used */ + USHORT uiParents; /* Number of parents for this area */ + USHORT heap; + USHORT heapSize; + USHORT rddID; + USHORT uiMaxFieldNameLength; + PHB_CODEPAGE cdPage; /* Area's codepage pointer */ + + /* + * SQLBASE additions to the workarea structure + */ + + LPDBRELINFO lpdbPendingRel; + + ULONG ulConnection; + struct _SQLDDCONNECTION* pConnection; + struct _SDDNODE* pSDD; + + char* szQuery; /* SQL query */ + + ULONG ulRecNo; /* Current record number */ + ULONG ulRecCount; /* Total records */ + ULONG ulRecMax; /* Size of pRow, pRowFlags buffer */ + + void** pRow; /* array of native pointers or cached PHB_ITEM */ + BYTE* pRowFlags; + + void* pRecord; + BYTE bRecordFlags; + + void* pResult; /* SQL result */ + void* pStmt; /* SQL statement */ + void* pTrans; /* SQL transaction */ + + void* pNatRecord; + void* pNatLength; + + BOOL fFetched; + BOOL fPositioned; + BOOL fAppend; + BOOL fRecordChanged; +} SQLBASEAREA, *SQLBASEAREAP; + + +typedef struct _SQLDDCONNECTION +{ + struct _SDDNODE * pSDD; + void* hConnection; + int iError; + char* szError; + char* szQuery; + PHB_ITEM pNewID; + ULONG ulAffectedRows; +} SQLDDCONNECTION; + + +//==================================================================== +// SQLMIX +//==================================================================== + +#define MIX_MAXKEYLEN 1024 +#define MIX_MAXTAGNAMELEN 16 + + +#define MIX_NODE_ORDER 2 // >=2 + + +typedef struct _MIXKEY +{ + ULONG rec; + BYTE notnul; + BYTE * val; +} MIXKEY, *PMIXKEY; + + +typedef struct _MIXNODE +{ + UINT Leaf; + UINT KeyCount; + struct _MIXNODE* Parent; + struct _MIXNODE* Child[ MIX_NODE_ORDER + 1 ]; +} MIXNODE, *PMIXNODE; + + +typedef struct _MIXNODELEAF +{ + UINT Leaf; + UINT KeyCount; + struct _MIXNODE* Parent; +} MIXNODELEAF, *PMIXNODELEAF; + + +typedef struct _MIXTAG +{ + struct _MIXTAG* pNext; + struct _SQLMIXAREA* pArea; + char* szName; + char* szKeyExpr; + char* szForExpr; + PHB_ITEM pKeyItem; + PHB_ITEM pForItem; + + BYTE bType; + UINT uiKeyLen; // Length of key + UINT uiTotalLen; // Total length of key structure + + BOOL fEof; + BOOL fBof; + BOOL fCustom; + + PMIXNODE Root; + + PMIXKEY CurKey; + PMIXNODE CurNode; + UINT CurPos; + + PMIXKEY HotKey; + BOOL HotFor; + + BYTE* pSortTable; // National sorttable for character key tags, NULL otherwise +} MIXTAG, *PMIXTAG; + + +typedef struct _SQLMIXAREA +{ + struct _RDDFUNCS * lprfsHost; /* Virtual method table for this workarea */ + USHORT uiArea; /* The number assigned to this workarea */ + void * atomAlias; /* Pointer to the alias symbol for this workarea */ + USHORT uiFieldExtent; /* Total number of fields allocated */ + USHORT uiFieldCount; /* Total number of fields used */ + LPFIELD lpFields; /* Pointer to an array of fields */ + void * lpFieldExtents; /* Void ptr for additional field properties */ + PHB_ITEM valResult; /* All purpose result holder */ + BOOL fTop; /* TRUE if "top" */ + BOOL fBottom; /* TRUE if "bottom" */ + BOOL fBof; /* TRUE if "bof" */ + BOOL fEof; /* TRUE if "eof" */ + BOOL fFound; /* TRUE if "found" */ + DBSCOPEINFO dbsi; /* Info regarding last LOCATE */ + DBFILTERINFO dbfi; /* Filter in effect */ + LPDBORDERCONDINFO lpdbOrdCondInfo; + LPDBRELINFO lpdbRelations; /* Parent/Child relationships used */ + USHORT uiParents; /* Number of parents for this area */ + USHORT heap; + USHORT heapSize; + USHORT rddID; + USHORT uiMaxFieldNameLength; + PHB_CODEPAGE cdPage; /* Area's codepage pointer */ + + /* + * SQLBASE additions to the workarea structure + */ + + LPDBRELINFO lpdbPendingRel; + + ULONG ulConnection; + struct _SQLDDCONNECTION* pConnection; + struct _SDDNODE* pSDD; + + char* szQuery; /* SQL query */ + + ULONG ulRecNo; /* Current record number */ + ULONG ulRecCount; /* Total records */ + ULONG ulRecMax; /* Size of pRow, pRowFlags buffer */ + + void** pRow; /* array of native pointers or cached PHB_ITEM */ + BYTE* pRowFlags; + + void* pRecord; + BYTE bRecordFlags; + + void* pResult; /* SQL result */ + void* pStmt; /* SQL statement */ + void* pTrans; /* SQL transaction */ + + void* pNatRecord; + void* pNatLength; + + BOOL fFetched; + BOOL fPositioned; + BOOL fAppend; + BOOL fRecordChanged; + + /* + * SQLMIX additions to the workarea structure + */ + + PMIXTAG pTagList; + PMIXTAG pTag; + BYTE* pSortTable; + +} SQLMIXAREA, *SQLMIXAREAP; + + + +//==================================================================== +// SQLDD +//==================================================================== + +typedef ERRCODE (* SDDFUNC_CONNECT )( SQLDDCONNECTION* pConnection, PHB_ITEM pItem ); +typedef ERRCODE (* SDDFUNC_DISCONNECT )( SQLDDCONNECTION* pConnection ); +typedef ERRCODE (* SDDFUNC_EXECUTE )( SQLDDCONNECTION* pConnection, PHB_ITEM pItem ); +typedef ERRCODE (* SDDFUNC_OPEN )( SQLBASEAREAP pArea ); +typedef ERRCODE (* SDDFUNC_CLOSE )( SQLBASEAREAP pArea ); +typedef ERRCODE (* SDDFUNC_GOTO )( SQLBASEAREAP pArea, ULONG ulRecNo ); +typedef ERRCODE (* SDDFUNC_GETVALUE )( SQLBASEAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ); +typedef ERRCODE (* SDDFUNC_GETVARLEN )( SQLBASEAREAP pArea, USHORT uiIndex, ULONG * pLength ); + + +typedef struct _SDDNODE +{ + struct _SDDNODE * pNext; + + char* Name; + SDDFUNC_CONNECT Connect; + SDDFUNC_DISCONNECT Disconnect; + SDDFUNC_EXECUTE Execute; + SDDFUNC_OPEN Open; + SDDFUNC_CLOSE Close; + SDDFUNC_GOTO GoTo; + SDDFUNC_GETVALUE GetValue; + SDDFUNC_GETVARLEN GetVarLen; +} SDDNODE, * PSDDNODE; + + +int hb_sddRegister( PSDDNODE pSdd ); + + + +//==================================================================== +// Misc +//==================================================================== + +// Error subcodes +#define ESQLDD_NOTCONNECTED 1901 +#define ESQLDD_INVALIDFIELD 1902 +#define ESQLDD_INVALIDQUERY 1903 +#define ESQLDD_START 1904 +#define ESQLDD_COMMIT 1905 +#define ESQLDD_STMTALLOC 1906 +#define ESQLDD_STMTDESCR 1907 +#define ESQLDD_STMTFREE 1908 +#define ESQLDD_FETCH 1909 +#define ESQLDD_LOWMEMORY 1910 + +#endif diff --git a/harbour/contrib/rddsql/make_b32.bat b/harbour/contrib/rddsql/make_b32.bat new file mode 100644 index 0000000000..d08daf16cc --- /dev/null +++ b/harbour/contrib/rddsql/make_b32.bat @@ -0,0 +1,69 @@ +@echo off +rem +rem $Id$ +rem + +if not "%HB_INC_MYSQL%%HB_DIR_MYSQL%" == "" goto DIR_OK + +echo --------------------------------------------------------------- +echo IMPORTANT: You'll need MySQL package and this envvar +echo to be set to successfully build this library: +echo set HB_INC_MYSQL=C:\mysql\include +echo or +echo set HB_DIR_MYSQL=C:\mysql +echo if you want to generate .lib for the .dll. +echo --------------------------------------------------------------- +goto POST_EXIT + +:DIR_OK + +if "%HB_INC_MYSQL%" == "" set HB_INC_MYSQL=%HB_DIR_MYSQL%\include +set CFLAGS=-I"%HB_INC_MYSQL%" +set _HB_DLL_NAME=libmySQL +set _HB_DLL_DIR=%HB_DIR_MYSQL%\bin + +rem --------------------------------------------------------------- + +call ..\mtpl_b32.bat %1 %2 %3 %4 %5 %6 %7 %8 %9 + +rem --------------------------------------------------------------- + +if "%HB_DIR_MYSQL%" == "" goto POST_EXIT + +set _HB_INSTALL_PREFIX=%HB_INSTALL_PREFIX% +if "%_HB_INSTALL_PREFIX%" == "" set _HB_INSTALL_PREFIX=..\.. +set _HB_LIB_INSTALL=%HB_LIB_INSTALL% +if "%_HB_LIB_INSTALL%" == "" set _HB_LIB_INSTALL=%_HB_INSTALL_PREFIX%\lib + +if "%1" == "clean" goto POST_CLEAN +if "%1" == "Clean" goto POST_CLEAN +if "%1" == "CLEAN" goto POST_CLEAN +if "%1" == "install" goto POST_INSTALL +if "%1" == "Install" goto POST_INSTALL +if "%1" == "INSTALL" goto POST_INSTALL + +:POST_BUILD + + implib ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib "%_HB_DLL_DIR%\%_HB_DLL_NAME%.dll" >> %_HB_MAKELOG% + goto POST_EXIT + +:POST_CLEAN + + if exist ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib del ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib > nul + if exist ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.exp del ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.exp > nul + if exist %_HB_LIB_INSTALL%\%_HB_DLL_NAME%.lib del %_HB_LIB_INSTALL%\%_HB_DLL_NAME%.lib > nul + goto POST_EXIT + +:POST_INSTALL + + if exist %_HB_LIB_INSTALL%\%_HB_DLL_NAME%.lib del %_HB_LIB_INSTALL%\%_HB_DLL_NAME%.lib + if exist ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib copy ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib %_HB_LIB_INSTALL% + goto POST_EXIT + +:POST_EXIT + +set CFLAGS= +set _HB_DLL_NAME= +set _HB_DLL_DIR= +set _HB_INSTALL_PREFIX= +set _HB_LIB_INSTALL= diff --git a/harbour/contrib/rddsql/make_gcc.sh b/harbour/contrib/rddsql/make_gcc.sh new file mode 100755 index 0000000000..ead0b8cdda --- /dev/null +++ b/harbour/contrib/rddsql/make_gcc.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# +# $Id$ +# + +if [ "${HB_INC_MYSQL}" = "" ] +then + echo "---------------------------------------------------------------" + echo "IMPORTANT: You will need MYSQL package installed and this" + echo " envvar to be set to successfully build this library:" + echo " export HB_INC_MYSQL=C:/Mysql/include" + echo " or" + echo " export HB_INC_MYSQL=/usr/include/mysql" + echo "---------------------------------------------------------------" + exit 1 +fi + +export CFLAGS="" +for I in ${HB_INC_MYSQL}; do + CFLAGS="${CFLAGS} -I${I}" +done +../mtpl_gcc.sh $1 $2 $3 $4 $5 $6 $7 $8 $9 +unset CFLAGS diff --git a/harbour/contrib/rddsql/make_vc.bat b/harbour/contrib/rddsql/make_vc.bat new file mode 100644 index 0000000000..3a05f82e60 --- /dev/null +++ b/harbour/contrib/rddsql/make_vc.bat @@ -0,0 +1,70 @@ +@echo off +rem +rem $Id$ +rem + +if not "%HB_INC_MYSQL%%HB_DIR_MYSQL%" == "" goto DIR_OK + +echo --------------------------------------------------------------- +echo IMPORTANT: You'll need MySQL package and this envvar +echo to be set to successfully build this library: +echo set HB_INC_MYSQL=C:\mysql\include +echo or +echo set HB_DIR_MYSQL=C:\mysql +echo if you want to generate .lib for the .dll. +echo --------------------------------------------------------------- +goto POST_EXIT + +:DIR_OK + +if "%HB_INC_MYSQL%" == "" set HB_INC_MYSQL=%HB_DIR_MYSQL%\include +set CFLAGS=-I"%HB_INC_MYSQL%" +set _HB_DLL_NAME=libmySQL +set _HB_DLL_DIR=%HB_DIR_MYSQL%\bin + +rem --------------------------------------------------------------- + +call ..\mtpl_vc.bat %1 %2 %3 %4 %5 %6 %7 %8 %9 + +rem --------------------------------------------------------------- + +if "%HB_DIR_MYSQL%" == "" goto POST_EXIT + +set _HB_INSTALL_PREFIX=%HB_INSTALL_PREFIX% +if "%_HB_INSTALL_PREFIX%" == "" set _HB_INSTALL_PREFIX=..\.. +set _HB_LIB_INSTALL=%HB_LIB_INSTALL% +if "%_HB_LIB_INSTALL%" == "" set _HB_LIB_INSTALL=%_HB_INSTALL_PREFIX%\lib + +if "%1" == "clean" goto POST_CLEAN +if "%1" == "Clean" goto POST_CLEAN +if "%1" == "CLEAN" goto POST_CLEAN +if "%1" == "install" goto POST_INSTALL +if "%1" == "Install" goto POST_INSTALL +if "%1" == "INSTALL" goto POST_INSTALL + +:POST_BUILD + + rem Use supplied .lib file. + if not exist ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib copy "%HB_DIR_MYSQL%\lib\opt\%_HB_DLL_NAME%.lib" ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib > nul + goto POST_EXIT + +:POST_CLEAN + + if exist ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib del ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib > nul + if exist ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.exp del ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.exp > nul + if exist %_HB_LIB_INSTALL%\%_HB_DLL_NAME%.lib del %_HB_LIB_INSTALL%\%_HB_DLL_NAME%.lib > nul + goto POST_EXIT + +:POST_INSTALL + + if exist %_HB_LIB_INSTALL%\%_HB_DLL_NAME%.lib del %_HB_LIB_INSTALL%\%_HB_DLL_NAME%.lib + if exist ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib copy ..\..\lib\%_HB_CC_NAME%\%_HB_DLL_NAME%.lib %_HB_LIB_INSTALL% + goto POST_EXIT + +:POST_EXIT + +set CFLAGS= +set _HB_DLL_NAME= +set _HB_DLL_DIR= +set _HB_INSTALL_PREFIX= +set _HB_LIB_INSTALL= diff --git a/harbour/contrib/rddsql/mysqldd.c b/harbour/contrib/rddsql/mysqldd.c new file mode 100644 index 0000000000..58a5164713 --- /dev/null +++ b/harbour/contrib/rddsql/mysqldd.c @@ -0,0 +1,603 @@ +/* + * $Id$ + */ + +/* + * MySQL Database Driver + * + * Copyright 2007 Mindaugas Kavaliauskas + * 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 "hbapiitm.h" +#include "hbvm.h" +#include "hbsqldd.h" + +#ifndef my_socket_defined +#define my_socket_defined +typedef int my_socket; +#endif + +#include "mysql.h" + +#if sizeof( MYSQL_ROW_OFFSET ) != sizeof( void* ) + #error "MySQLDD error: sizeof( MYSQL_ROW_OFFSET ) != sizeof( void* )" +#endif + +#if sizeof( MYSQL_ROW ) != sizeof( void* ) + #error "MySQLDD error: sizeof( MYSQL_ROW ) != sizeof( void* )" +#endif + +#ifndef MYSQL_TYPE_NEWDECIMAL +#define MYSQL_TYPE_NEWDECIMAL 246 +#endif + + +static ERRCODE mysqlConnect( SQLDDCONNECTION* pConnection, PHB_ITEM pItem ); +static ERRCODE mysqlDisconnect( SQLDDCONNECTION* pConnection ); +static ERRCODE mysqlExecute( SQLDDCONNECTION* pConnection, PHB_ITEM pItem ); +static ERRCODE mysqlOpen( SQLBASEAREAP pArea ); +static ERRCODE mysqlClose( SQLBASEAREAP pArea ); +static ERRCODE mysqlGoTo( SQLBASEAREAP pArea, ULONG ulRecNo ); +static ERRCODE mysqlGetValue( SQLBASEAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ); +static ERRCODE mysqlGetVarLen( SQLBASEAREAP pArea, USHORT uiIndex, ULONG * pLength ); + + +static SDDNODE mysqldd = { + NULL, + "MYSQL", + (SDDFUNC_CONNECT) mysqlConnect, + (SDDFUNC_DISCONNECT) mysqlDisconnect, + (SDDFUNC_EXECUTE) mysqlExecute, + (SDDFUNC_OPEN) mysqlOpen, + (SDDFUNC_CLOSE) mysqlClose, + (SDDFUNC_GOTO) mysqlGoTo, + (SDDFUNC_GETVALUE) mysqlGetValue, + (SDDFUNC_GETVARLEN) mysqlGetVarLen +}; + + +HB_FUNC_EXTERN( SQLBASE ); + + +static void hb_mysqldd_init( void * cargo ) +{ + HB_SYMBOL_UNUSED( cargo ); + + if ( ! hb_sddRegister( & mysqldd ) ) + { + hb_errInternal( HB_EI_RDDINVALID, NULL, NULL, NULL ); + HB_FUNC_EXEC( SQLBASE ); // force SQLBASE linking + } +} + + +#define __PRG_SOURCE__ __FILE__ + +#ifdef HB_PCODE_VER + #undef HB_PRG_PCODE_VER + #define HB_PRG_PCODE_VER HB_PCODE_VER +#endif + + +HB_FUNC( MYSQLDD ) {;} + + +HB_INIT_SYMBOLS_BEGIN( mysqldd__InitSymbols ) +{ "MYSQLDD", HB_FS_PUBLIC, HB_FUNCNAME( MYSQLDD ), NULL }, +HB_INIT_SYMBOLS_END( mysqldd__InitSymbols ) + + +HB_CALL_ON_STARTUP_BEGIN( _hb_mysqldd_init_ ) + hb_vmAtInit( hb_mysqldd_init, NULL ); +HB_CALL_ON_STARTUP_END( _hb_mysqldd_init_ ) + + +#if defined(HB_PRAGMA_STARTUP) + #pragma startup mysqldd__InitSymbols + #pragma startup _hb_mysqldd_init_ +#elif defined(_MSC_VER) + #if _MSC_VER >= 1010 + #pragma data_seg( ".CRT$XIY" ) + #pragma comment( linker, "/Merge:.CRT=.data" ) + #else + #pragma data_seg( "XIY" ) + #endif + static HB_$INITSYM hb_vm_auto_mysqldd__InitSymbols = mysqldd__InitSymbols; + static HB_$INITSYM hb_vm_auto_mysqldd_init = _hb_mysqldd_init_; + #pragma data_seg() +#endif + + +//===================================================================================== +static USHORT hb_errRT_MySQLDD( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation, USHORT uiOsCode ) +{ + USHORT uiAction; + PHB_ITEM pError; + + pError = hb_errRT_New( ES_ERROR, "MYSQLDD", ulGenCode, ulSubCode, szDescription, szOperation, uiOsCode, EF_NONE ); + + uiAction = hb_errLaunch( pError ); + + hb_itemRelease( pError ); + + return uiAction; +} + +//============= SDD METHODS ============================================================= + +static ERRCODE mysqlConnect( SQLDDCONNECTION* pConnection, PHB_ITEM pItem ) +{ + MYSQL* pMySql; + +// TraceLog( NULL, "mysqlConnect type:%04X s2:%s s3:%s s4:%s s5:%s\n", pItem->type, hb_arrayGetCPtr( pItem, 2 ), hb_arrayGetCPtr( pItem, 3 ), hb_arrayGetCPtr( pItem, 4 ), hb_arrayGetCPtr( pItem, 5 ) ); + + pMySql = mysql_init( NULL ); + if ( ! mysql_real_connect( pMySql, hb_arrayGetCPtr( pItem, 2 ), hb_arrayGetCPtr( pItem, 3 ), hb_arrayGetCPtr( pItem, 4 ), + hb_arrayGetCPtr( pItem, 5 ), 0 /* port */, NULL /* pipe */, 0 /* flags*/ ) ) + { + mysql_close( pMySql ); + return FAILURE; + } + pConnection->hConnection = (void*) pMySql; + return SUCCESS; +} + + +static ERRCODE mysqlDisconnect( SQLDDCONNECTION* pConnection ) +{ + mysql_close( pConnection->hConnection ); + return SUCCESS; +} + + +static ERRCODE mysqlExecute( SQLDDCONNECTION* pConnection, PHB_ITEM pItem ) +{ + MYSQL_RES* pResult; + + if ( mysql_real_query( (MYSQL*) pConnection->hConnection, hb_itemGetCPtr( pItem ), hb_itemGetCLen( pItem ) ) ) + { + const char* szError; + + pConnection->iError = (int) mysql_errno( (MYSQL*) pConnection->hConnection ); + szError = mysql_error( (MYSQL*) pConnection->hConnection ); + if ( pConnection->szError ) + pConnection->szError = hb_xrealloc( pConnection->szError, strlen( szError ) + 1 ); + else + pConnection->szError = hb_xgrab( strlen( szError ) + 1 ); + hb_strncpy( pConnection->szError, szError, strlen( szError ) ); + return FAILURE; + } + + pResult = mysql_store_result( (MYSQL*) pConnection->hConnection ); + if ( pResult ) + { + pConnection->ulAffectedRows = (ULONG) mysql_num_rows( pResult ); + mysql_free_result( pResult ); + } + else + { + if ( mysql_field_count( (MYSQL*) pConnection->hConnection ) == 0 ) + { + pConnection->ulAffectedRows = (ULONG) mysql_affected_rows( (MYSQL*) pConnection->hConnection ); + if ( mysql_insert_id( (MYSQL*) pConnection->hConnection ) != 0 ) + hb_itemPutNInt( pConnection->pNewID, mysql_insert_id( (MYSQL*) pConnection->hConnection ) ); + } + else // error + { + const char* szError; + + pConnection->iError = (int) mysql_errno( (MYSQL*) pConnection->hConnection ); + szError = mysql_error( (MYSQL*) pConnection->hConnection ); + if ( pConnection->szError ) + pConnection->szError = hb_xrealloc( pConnection->szError, strlen( szError ) + 1 ); + else + pConnection->szError = hb_xgrab( strlen( szError ) + 1 ); + hb_strncpy( pConnection->szError, szError, strlen( szError ) ); + return FAILURE; + } + } + return SUCCESS; +} + + +static ERRCODE mysqlOpen( SQLBASEAREAP pArea ) +{ + PHB_ITEM pItemEof, pItem; + ULONG ulIndex; + USHORT uiFields, uiCount, uiError = 0; + BOOL bError; + BYTE* pBuffer; + DBFIELDINFO pFieldInfo; + MYSQL_FIELD* pMyField; + void** pRow; + + if ( mysql_real_query( (MYSQL*) pArea->pConnection->hConnection, pArea->szQuery, strlen( pArea->szQuery ) ) ) + { + hb_errRT_MySQLDD( EG_OPEN, ESQLDD_INVALIDQUERY, (char*) mysql_error( (MYSQL*) pArea->pConnection->hConnection ), pArea->szQuery, + mysql_errno( (MYSQL*) pArea->pConnection->hConnection ) ); + return FAILURE; + } + + if ( ( pArea->pResult = mysql_store_result( (MYSQL*) pArea->pConnection->hConnection ) ) == NULL ) + { + hb_errRT_MySQLDD( EG_MEM, ESQLDD_INVALIDQUERY, (char*) mysql_error( (MYSQL*) pArea->pConnection->hConnection ), pArea->szQuery, + mysql_errno( (MYSQL*) pArea->pConnection->hConnection ) ); + return FAILURE; + } + + // TODO: o kokiu atveju jau gali buti laukai? kaip tada su pItemEof priskyrimu? + if ( ! pArea->uiFieldCount ) + { + uiFields = mysql_num_fields( (MYSQL_RES*) pArea->pResult ); + SELF_SETFIELDEXTENT( (AREAP) pArea, uiFields ); + + pItemEof = hb_itemArrayNew( uiFields ); + + pBuffer = (BYTE*) hb_xgrab( 256 ); + + bError = FALSE; + for ( uiCount = 0; uiCount < uiFields; uiCount++ ) + { + pMyField = mysql_fetch_field_direct( (MYSQL_RES*) pArea->pResult, uiCount ); + + hb_strncpy( pBuffer, pMyField->name, 256 - 1 ); + pFieldInfo.atomName = pBuffer; + pFieldInfo.atomName[ MAX_FIELD_NAME ] = '\0'; + hb_strUpper( (char *) pFieldInfo.atomName, MAX_FIELD_NAME + 1 ); + + pFieldInfo.uiLen = pMyField->length; + pFieldInfo.uiDec = 0; + + switch( pMyField->type ) + { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + pFieldInfo.uiType = HB_FT_INTEGER; + break; + + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + pFieldInfo.uiType = HB_FT_LONG; + break; + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + pFieldInfo.uiType = HB_FT_DOUBLE; + pFieldInfo.uiDec = pMyField->decimals; + break; + + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_DATETIME: + pFieldInfo.uiType = HB_FT_STRING; + break; + + case MYSQL_TYPE_DATE: + pFieldInfo.uiType = HB_FT_DATE; + break; + + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + pFieldInfo.uiType = HB_FT_MEMO; + break; + +// case MYSQL_TYPE_TIMESTAMP: +// case MYSQL_TYPE_TIME: +// case MYSQL_TYPE_DATETIME: +// case MYSQL_TYPE_YEAR: +// case MYSQL_TYPE_NEWDATE: +// case MYSQL_TYPE_ENUM: +// case MYSQL_TYPE_SET: + + default: + bError = TRUE; + uiError = (USHORT) pMyField->type; + break; + } + + if ( ! bError ) + { + switch ( pFieldInfo.uiType ) + { + case HB_FT_STRING: + { + char* pStr; + + pStr = (char*) hb_xgrab( pFieldInfo.uiLen + 1 ); + memset( pStr, ' ', pFieldInfo.uiLen ); + pStr[ pFieldInfo.uiLen ] = '\0'; + + pItem = hb_itemPutCL( NULL, pStr, pFieldInfo.uiLen ); + hb_xfree( pStr ); + break; + } + + case HB_FT_MEMO: + pItem = hb_itemPutC( NULL, "" ); + break; + + case HB_FT_INTEGER: + pItem = hb_itemPutNI( NULL, 0 ); + break; + + case HB_FT_LONG: + pItem = hb_itemPutNL( NULL, 0 ); + break; + + case HB_FT_DOUBLE: + pItem = hb_itemPutND( NULL, 0.0 ); + break; + + case HB_FT_DATE: + pItem = hb_itemPutDS( NULL, "" ); + break; + + default: + pItem = hb_itemNew( NULL ); + bError = TRUE; + break; + } + + hb_arraySetForward( pItemEof, uiCount + 1, pItem ); + hb_itemRelease( pItem ); + +/* if ( pFieldInfo.uiType == HB_IT_DOUBLE || pFieldInfo.uiType == HB_IT_INTEGER ) + { + pFieldInfo.uiType = HB_IT_LONG; + }*/ + + if ( ! bError ) + bError = ( SELF_ADDFIELD( (AREAP) pArea, &pFieldInfo ) == FAILURE ); + } + + if ( bError ) + break; + } + + hb_xfree( pBuffer ); + + if ( bError ) + { + hb_itemRelease( pItemEof ); + hb_errRT_MySQLDD( EG_CORRUPTION, ESQLDD_INVALIDFIELD, "Invalid field type", pArea->szQuery, uiError ); + return FAILURE; + } + } + + pArea->ulRecCount = (ULONG) mysql_num_rows( (MYSQL_RES*) pArea->pResult ); + + pArea->pRow = (void**) hb_xgrab( ( pArea->ulRecCount + 1 ) * sizeof( void* ) ); + pArea->pRowFlags = (BYTE*) hb_xgrab( ( pArea->ulRecCount + 1 ) * sizeof( BYTE ) ); + memset( pArea->pRowFlags, 0, ( pArea->ulRecCount + 1 ) * sizeof( BYTE ) ); + pArea->ulRecMax = pArea->ulRecCount + 1; + + pRow = pArea->pRow; + + *pRow = pItemEof; + pArea->pRowFlags[ 0 ] = SQLDD_FLAG_CACHED; + + pRow++; + for ( ulIndex = 1; ulIndex <= pArea->ulRecCount; ulIndex++ ) + { + *pRow++ = (void*) mysql_row_tell( (MYSQL_RES*) pArea->pResult ); + mysql_fetch_row( (MYSQL_RES*) pArea->pResult ); + } + pArea->fFetched = 1; + + return SUCCESS; +} + + +static ERRCODE mysqlClose( SQLBASEAREAP pArea ) +{ + if ( pArea->pResult ) + mysql_free_result( (MYSQL_RES*) pArea->pResult ); + return SUCCESS; +} + + +static ERRCODE mysqlGoTo( SQLBASEAREAP pArea, ULONG ulRecNo ) +{ + if ( ulRecNo <= 0 || ulRecNo > pArea->ulRecCount ) + { + pArea->pRecord = pArea->pRow[ 0 ]; + pArea->bRecordFlags = pArea->pRowFlags[ 0 ]; + + pArea->fPositioned = FALSE; + } + else + { + pArea->pRecord = pArea->pRow[ ulRecNo ]; + pArea->bRecordFlags = pArea->pRowFlags[ ulRecNo ]; + + if ( ! ( pArea->bRecordFlags & SQLDD_FLAG_CACHED ) ) + { + mysql_row_seek( (MYSQL_RES*) pArea->pResult, pArea->pRecord ); + pArea->pNatRecord = (void*) mysql_fetch_row( (MYSQL_RES*) pArea->pResult ); + pArea->pNatLength = (void*) mysql_fetch_lengths( (MYSQL_RES*) pArea->pResult ); + } + + pArea->fPositioned = TRUE; + } + return SUCCESS; +} + + +static ERRCODE mysqlGetValue( SQLBASEAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) +{ + LPFIELD pField; + char* pValue; + char szBuffer[ 64 ]; + BOOL bError; + PHB_ITEM pError; + ULONG ulLen; + + bError = FALSE; + uiIndex--; + pField = pArea->lpFields + uiIndex; + + pValue = ( (MYSQL_ROW) ( pArea->pNatRecord ) ) [ uiIndex ]; + ulLen = ( (unsigned long*) ( pArea->pNatLength ) ) [ uiIndex ]; + + // NULL => NIL (?) + if ( ! pValue ) + { + hb_itemClear( pItem ); + return SUCCESS; + } + + switch( pField->uiType ) + { + case HB_FT_STRING: + { +#if 0 + char* pStr; + + // Do NOT trim strings + pStr = (char*) hb_xgrab( pField->uiLen + 1 ); + if ( pValue ) + memcpy( pStr, pValue, ulLen ); + + if ( (ULONG)pField->uiLen > ulLen ) + memset( pStr + ulLen, ' ', pField->uiLen - ulLen ); + + pStr[ pField->uiLen ] = '\0'; + hb_itemPutCRaw( pItem, pStr, pField->uiLen ); +#else + // Trim strings + if ( pValue ) + hb_itemPutCL( pItem, pValue, ulLen ); + else + hb_itemPutCL( pItem, "", 0 ); +#endif + break; + } + + case HB_FT_MEMO: + if ( pValue ) + hb_itemPutCL( pItem, pValue, ulLen ); + else + hb_itemPutCL( pItem, "", 0 ); + + hb_itemSetCMemo( pItem ); + break; + + case HB_FT_INTEGER: + case HB_FT_LONG: + case HB_FT_DOUBLE: + if ( pValue ) + { + hb_strncpy( szBuffer, pValue, sizeof( szBuffer ) - 1 ); + + if ( pField->uiDec ) + { + hb_itemPutNDLen( pItem, atof( szBuffer ), + (int) pField->uiLen - ( (int) pField->uiDec + 1 ), + (int) pField->uiDec ); + } + else + hb_itemPutNLLen( pItem, atol( szBuffer ), (int) pField->uiLen ); + } + else + { + if ( pField->uiDec ) + hb_itemPutNDLen( pItem, 0.0, + (int) pField->uiLen - ( (int) pField->uiDec + 1 ), + (int) pField->uiDec ); + else + hb_itemPutNLLen( pItem, 0, (int) pField->uiLen ); + } + break; + + case HB_FT_DATE: + { + char szDate[ 9 ]; + + szDate[ 0 ] = pValue[ 0 ]; + szDate[ 1 ] = pValue[ 1 ]; + szDate[ 2 ] = pValue[ 2 ]; + szDate[ 3 ] = pValue[ 3 ]; + szDate[ 4 ] = pValue[ 5 ]; + szDate[ 5 ] = pValue[ 6 ]; + szDate[ 6 ] = pValue[ 8 ]; + szDate[ 7 ] = pValue[ 9 ]; + szDate[ 8 ] = '\0'; + hb_itemPutDS( pItem, szDate ); + break; + } + + default: + bError = TRUE; + break; + } + + if ( bError ) + { + pError = hb_errNew(); + hb_errPutGenCode( pError, EG_DATATYPE ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATATYPE ) ); + hb_errPutSubCode( pError, EDBF_DATATYPE ); + SELF_ERROR( ( AREAP ) pArea, pError ); + hb_itemRelease( pError ); + return FAILURE; + } + return SUCCESS; +} + + +static ERRCODE mysqlGetVarLen( SQLBASEAREAP pArea, USHORT uiIndex, ULONG * pLength ) +{ + HB_SYMBOL_UNUSED( pArea ); + HB_SYMBOL_UNUSED( uiIndex ); + HB_SYMBOL_UNUSED( pLength ); + return SUCCESS; +} diff --git a/harbour/contrib/rddsql/sqlbase.c b/harbour/contrib/rddsql/sqlbase.c new file mode 100644 index 0000000000..5ab356b91b --- /dev/null +++ b/harbour/contrib/rddsql/sqlbase.c @@ -0,0 +1,1154 @@ +/* + * $Id$ + */ + +/* + * SQL Base Database Driver + * + * Copyright 2007 Mindaugas Kavaliauskas + * 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 "hbapiitm.h" +#include "hbvm.h" +#include "hbset.h" +#include "hbsqldd.h" +#include "rddsys.ch" + + +#define SUPERTABLE ( &sqlbaseSuper ) + +#define CONNECTION_LIST_EXPAND 4 + + +//==================== SDD registration ===================================== + +static PSDDNODE s_pSdd = NULL; + + +int hb_sddRegister( PSDDNODE pSdd ) +{ + PSDDNODE pNode = s_pSdd; + + while ( pNode ) + { + if ( ! hb_stricmp( pNode->Name, pSdd->Name ) ) + return 0; + pNode = pNode->pNext; + } + pSdd->pNext = s_pSdd; + s_pSdd = pSdd; + return 1; +} + + + +//==================== SQLBASE code =========================================== + +static USHORT s_rddidSQLBASE = 0; +static SQLDDCONNECTION* s_pConnection = NULL; +static ULONG s_ulConnectionCount = 0; +static ULONG s_ulConnectionCurrent = 0; + +static RDDFUNCS sqlbaseSuper; + + +static ERRCODE hb_errRT_SQLBASE( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation ) +{ + PHB_ITEM pError; + ERRCODE iRet = FAILURE; + + if ( hb_vmRequestQuery() == 0 ) + { + pError = hb_errRT_New( ES_ERROR, "SQLBASE", ulGenCode, ulSubCode, szDescription, szOperation, 0, EF_NONE ); + iRet = hb_errLaunch( pError ); + hb_itemRelease( pError ); + } + return iRet; +} + + +//============= RDD METHODS ============================================================= + +static ERRCODE sqlbaseGoBottom( SQLBASEAREAP pArea ) +{ + if ( SELF_GOCOLD( (AREAP) pArea ) == FAILURE ) + return FAILURE; + + + if ( ! pArea->fFetched && pArea->pSDD->GoTo( pArea, (ULONG) -1 ) == FAILURE ) + return FAILURE; + + pArea->fTop = FALSE; + pArea->fBottom = TRUE; + + if ( SELF_GOTO( (AREAP) pArea, pArea->ulRecCount ) != SUCCESS ) + return FAILURE; + + return SELF_SKIPFILTER( (AREAP) pArea, -1 ); +} + + +static ERRCODE sqlbaseGoTo( SQLBASEAREAP pArea, ULONG ulRecNo ) +{ + if ( SELF_GOCOLD( (AREAP) pArea ) == FAILURE ) + return FAILURE; + + if ( pArea->pSDD->GoTo( pArea, ulRecNo ) == FAILURE ) + return FAILURE; + + if ( pArea->fPositioned ) + { + pArea->ulRecNo = ulRecNo; + pArea->fBof = pArea->fEof = FALSE; + } + else + { + pArea->ulRecNo = pArea->ulRecCount + 1; + pArea->fBof = pArea->fEof = TRUE; + } + pArea->fFound = FALSE; + + return SUCCESS; +} + + +static ERRCODE sqlbaseGoToId( SQLBASEAREAP pArea, PHB_ITEM pItem ) +{ + PHB_ITEM pError; + + if ( HB_IS_NUMERIC( pItem ) ) + return SELF_GOTO( (AREAP) pArea, hb_itemGetNL( pItem ) ); + else + { + pError = hb_errNew(); + hb_errPutGenCode( pError, EG_DATATYPE ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATATYPE ) ); + hb_errPutSubCode( pError, EDBF_DATATYPE ); + SELF_ERROR( (AREAP) pArea, pError ); + hb_itemRelease( pError ); + return FAILURE; + } +} + + +static ERRCODE sqlbaseGoTop( SQLBASEAREAP pArea ) +{ + pArea->fTop = TRUE; + pArea->fBottom = FALSE; + + if ( SELF_GOTO( (AREAP) pArea, 1 ) == FAILURE ) + return FAILURE; + + return SELF_SKIPFILTER( (AREAP) pArea, 1 ); +} + + +static ERRCODE sqlbaseSkip( SQLBASEAREAP pArea, LONG lToSkip ) +{ + ERRCODE uiError; + + if ( pArea->lpdbPendingRel ) + { + if ( SELF_FORCEREL( ( AREAP ) pArea ) != SUCCESS ) + return FAILURE; + } + + pArea->fTop = pArea->fBottom = FALSE; + + if ( lToSkip == 0 || hb_setGetDeleted() || + pArea->dbfi.itmCobExpr || pArea->dbfi.fFilter ) + return SUPER_SKIP( (AREAP) pArea, lToSkip ); + + uiError = SELF_SKIPRAW( (AREAP) pArea, lToSkip ); + + /* Move first record and set Bof flag */ + if ( uiError == SUCCESS && pArea->fBof && lToSkip < 0 ) + { + uiError = SELF_GOTOP( (AREAP) pArea ); + pArea->fBof = TRUE; + } + + if ( lToSkip < 0 ) + pArea->fEof = FALSE; + else /* if ( lToSkip > 0 ) */ + pArea->fBof = FALSE; + + return uiError; +} + + +static ERRCODE sqlbaseSkipRaw( SQLBASEAREAP pArea, LONG lToSkip ) +{ + ERRCODE uiError; + + if ( pArea->lpdbPendingRel ) + { + if ( SELF_FORCEREL( ( AREAP ) pArea ) != SUCCESS ) + return FAILURE; + } + + if ( lToSkip == 0 ) + { + // TODO: maybe gocold is enough here! + BOOL bBof, bEof; + + /* Save flags */ + bBof = pArea->fBof; + bEof = pArea->fEof; + + uiError = SELF_GOTO( (AREAP) pArea, pArea->ulRecNo ); + + /* Restore flags */ + pArea->fBof = bBof; + pArea->fEof = bEof; + } + else if ( lToSkip < 0 && (ULONG) ( -lToSkip ) >= pArea->ulRecNo ) + { + uiError = SELF_GOTO( (AREAP) pArea, 1 ); + pArea->fBof = TRUE; + } + else + { + uiError = SELF_GOTO( (AREAP) pArea, pArea->ulRecNo + lToSkip ); + } + + return uiError; +} + + +static ERRCODE sqlbaseAppend( SQLBASEAREAP pArea, BOOL bUnLockAll ) +{ +/* + PHB_ITEM pArray; + PHB_ITEM pItem; + USHORT us; +*/ + + HB_SYMBOL_UNUSED( bUnLockAll ); + + // This GOTO is GOCOLD + GOEOF + if ( SELF_GOTO( ( AREAP ) pArea, 0 ) == FAILURE ) + return FAILURE; + + if ( ! pArea->fRecordChanged && SELF_GOHOT( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( pArea->ulRecCount + 1 >= pArea->ulRecMax ) + { + pArea->pRow = (void**) hb_xrealloc( pArea->pRow, ( pArea->ulRecMax + SQLDD_ROWSET_RESIZE ) * sizeof( void* ) ); + pArea->pRowFlags = (BYTE*) hb_xrealloc( pArea->pRowFlags, ( pArea->ulRecMax + SQLDD_ROWSET_RESIZE ) * sizeof( BYTE ) ); + pArea->ulRecMax += SQLDD_ROWSET_RESIZE; + } + +/* Sita padaro GOHOT + pArray = hb_itemNew( NULL ); + hb_arrayNew( pArray, pArea->uiFieldCount ); + for ( us = 1; us <= pArea->uiFieldCount; us++ ) + { + pItem = hb_itemNew( NULL ); + if ( SELF_GETVALUE( (AREAP) pArea, us, pItem ) == SUCCESS ) + hb_arraySetForward( pArray, us, pItem ); + + hb_itemRelease( pItem ); + } + pArea->pRecord = pArray; + pArea->bRecordFlags = SQLDD_FLAG_CACHED; + pArea->fRecordChanged = TRUE; +*/ + pArea->fAppend = pArea->fPositioned = TRUE; + pArea->ulRecCount++; + pArea->ulRecNo = pArea->ulRecCount; + pArea->fBof = pArea->fEof = pArea->fFound = FALSE; + return SUCCESS; +} + + +static ERRCODE sqlbaseDeleteRec( SQLBASEAREAP pArea ) +{ + if ( ! pArea->fPositioned ) + return SUCCESS; + + if ( ! pArea->fRecordChanged && SELF_GOHOT( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + pArea->bRecordFlags |= SQLDD_FLAG_DELETED; + return SUCCESS; +} + + +static ERRCODE sqlbaseDeleted( SQLBASEAREAP pArea, BOOL* pDeleted ) +{ + * pDeleted = pArea->bRecordFlags & SQLDD_FLAG_DELETED; + return SUCCESS; +} + +static ERRCODE sqlbaseGetValue( SQLBASEAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) +{ + if ( pArea->bRecordFlags & SQLDD_FLAG_CACHED ) + { + hb_arrayGet( pArea->pRecord, uiIndex, pItem ); + return SUCCESS; + } + return pArea->pSDD->GetValue( pArea, uiIndex, pItem ); +} + + +static ERRCODE sqlbaseGetVarLen( SQLBASEAREAP pArea, USHORT uiIndex, ULONG * pLength ) +{ + /* gal turi priklaustyi nuo Native... + if ( pArea->lpFields[ uiIndex ].uiType == HB_IT_MEMO ) + { + return pArea->pSDD->GetVarLen( pArea, uiIndex, pLength ); + } + */ + + * pLength = pArea->lpFields[ uiIndex - 1 ].uiLen; + return SUCCESS; +} + + +static 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 = FALSE; + pArea->fAppend = FALSE; + } + return SUCCESS; +} + + +static ERRCODE sqlbaseGoHot( SQLBASEAREAP pArea ) +{ + PHB_ITEM pArray, pItem; + USHORT us; + + pArray = hb_itemNew( NULL ); + hb_arrayNew( pArray, pArea->uiFieldCount ); + for ( us = 1; us <= pArea->uiFieldCount; us++ ) + { + pItem = hb_itemNew( NULL ); + if ( SELF_GETVALUE( (AREAP) pArea, us, pItem ) == SUCCESS ) + hb_arraySetForward( pArray, us, pItem ); + hb_itemRelease( pItem ); + } + pArea->pRecord = pArray; + pArea->bRecordFlags |= SQLDD_FLAG_CACHED; + pArea->fRecordChanged = TRUE; + return SUCCESS; +} + + +static ERRCODE sqlbasePutValue( SQLBASEAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) +{ + LPFIELD pField; + ERRCODE uiError; + + if ( ! pArea->fPositioned ) + return SUCCESS; + + if ( ! pArea->fRecordChanged && SELF_GOHOT( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + uiError = SUCCESS; + pField = pArea->lpFields + ( uiIndex - 1 ); + + if ( ( ( HB_IS_MEMO( pItem ) || HB_IS_STRING( pItem ) ) && pField->uiType == HB_FT_STRING ) || + ( HB_IS_DATE( pItem ) && pField->uiType == HB_FT_DATE ) || + ( 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 ) || + HB_IS_NIL( pItem ) ) + { + hb_arraySet( 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, uiError ); + hb_errPutFlags( pError, EF_CANDEFAULT ); + uiError = SELF_ERROR( (AREAP) pArea, pError ); + hb_itemRelease( pError ); + return uiError == E_DEFAULT ? SUCCESS : FAILURE; + } + return SUCCESS; +} + + +static ERRCODE sqlbaseRecall( SQLBASEAREAP pArea ) +{ + if ( ! pArea->fPositioned ) + return SUCCESS; + + if ( ! pArea->fRecordChanged && SELF_GOHOT( ( AREAP ) pArea ) != SUCCESS ) + return FAILURE; + + pArea->bRecordFlags &= ~SQLDD_FLAG_DELETED; + return SUCCESS; +} + + +static ERRCODE sqlbaseRecCount( SQLBASEAREAP pArea, ULONG * pRecCount ) +{ + * pRecCount = pArea->ulRecCount; + return SUCCESS; +} + + +static ERRCODE sqlbaseRecNo( SQLBASEAREAP pArea, ULONG * ulRecNo ) +{ + * ulRecNo = pArea->ulRecNo; + return SUCCESS; +} + + +static ERRCODE sqlbaseRecId( SQLBASEAREAP pArea, PHB_ITEM pRecNo ) +{ + ERRCODE errCode; + ULONG ulRecNo; + + errCode = SELF_RECNO( (AREAP) pArea, &ulRecNo ); + hb_itemPutNInt( pRecNo, ulRecNo ); + return errCode; +} + + +// TODO: pSortTable +static ERRCODE sqlbaseClose( SQLBASEAREAP pArea ) +{ + if ( SELF_GOCOLD( (AREAP) pArea ) == FAILURE ) + return FAILURE; + + if ( SUPER_CLOSE( (AREAP) pArea ) == FAILURE ) + return FAILURE; + + pArea->pSDD->Close( pArea ); + + if ( pArea->pRow ) + { + 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 ); + } + + if ( pArea->szQuery ) + hb_xfree( pArea->szQuery ); + + return SUCCESS; +} + + +static ERRCODE sqlbaseCreate( SQLBASEAREAP pArea, LPDBOPENINFO pOpenInfo ) +{ + PHB_ITEM pItemEof, pItem; + USHORT uiCount; + BOOL bError; + + pArea->ulConnection = pOpenInfo->ulConnection ? pOpenInfo->ulConnection : s_ulConnectionCurrent; + + if ( pArea->ulConnection < 0 || pArea->ulConnection > s_ulConnectionCount || + ( pArea->ulConnection && ! s_pConnection[ pArea->ulConnection - 1 ].hConnection ) ) + { + hb_errRT_SQLBASE( EG_OPEN, ESQLDD_NOTCONNECTED, "Not connected", NULL ); + return FAILURE; + } + + if ( pArea->ulConnection ) + { + pArea->pConnection = & s_pConnection[ pArea->ulConnection - 1 ]; + pArea->pSDD = pArea->pConnection->pSDD; + } + + pItemEof = hb_itemArrayNew( pArea->uiFieldCount ); + + bError = FALSE; + for ( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ ) + { + LPFIELD pField = pArea->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, "" ); + 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, "" ); + break; + + case HB_FT_LOGICAL: + pItem = hb_itemPutL( NULL, FALSE ); + break; + + default: + pItem = hb_itemNew( NULL ); + bError = 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( (AREAP) pArea ); + return FAILURE; + } + + pArea->ulRecCount = 0; + + pArea->pRow = (void**) hb_xalloc( SQLDD_ROWSET_RESIZE * sizeof( void* ) ); + pArea->pRowFlags = (BYTE*) hb_xalloc( SQLDD_ROWSET_RESIZE * sizeof( BYTE ) ); + pArea->ulRecMax = SQLDD_ROWSET_RESIZE; + + * (pArea->pRow) = pItemEof; + pArea->pRowFlags[ 0 ] = SQLDD_FLAG_CACHED; + pArea->fFetched = 1; + + if ( SUPER_CREATE( (AREAP) pArea, pOpenInfo ) != SUCCESS ) + { + SELF_CLOSE( (AREAP) pArea ); + return FAILURE; + } + return SELF_GOTOP( (AREAP) pArea ); +} + + +static ERRCODE sqlbaseInfo( SQLBASEAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) +{ + switch( uiIndex ) + { + case DBI_QUERY: + hb_itemPutC( pItem, pArea->szQuery ); + break; + } + + return SUCCESS; +} + + +static ERRCODE sqlbaseOpen( SQLBASEAREAP pArea, LPDBOPENINFO pOpenInfo ) +{ + ERRCODE errCode; + + pArea->ulConnection = pOpenInfo->ulConnection ? pOpenInfo->ulConnection : s_ulConnectionCurrent; + + if ( pArea->ulConnection <= 0 || pArea->ulConnection > s_ulConnectionCount || + ! s_pConnection[ pArea->ulConnection - 1 ].hConnection ) + { + hb_errRT_SQLBASE( EG_OPEN, ESQLDD_NOTCONNECTED, "Not connected", NULL ); + return FAILURE; + } + + pArea->pConnection = & s_pConnection[ pArea->ulConnection - 1 ]; + pArea->pSDD = pArea->pConnection->pSDD; + + // filename is a query + pArea->szQuery = (char*) hb_strdup( (char*) pOpenInfo->abName ); + + errCode = pArea->pSDD->Open( pArea ); + + if ( errCode == SUCCESS ) + { + errCode = SUPER_OPEN( (AREAP) pArea, pOpenInfo ); + } + + if( errCode != SUCCESS ) + { + SELF_CLOSE( (AREAP) pArea ); + return FAILURE; + } + return SELF_GOTOP( (AREAP) pArea ); +} + + +static ERRCODE sqlbaseStructSize( SQLBASEAREAP pArea, USHORT * uiSize ) +{ + HB_SYMBOL_UNUSED( pArea ); + + * uiSize = sizeof( SQLBASEAREA ); + return SUCCESS; +} + + +/* +static ERRCODE sqlbaseChildEnd( SQLBASEAREAP pArea, LPDBRELINFO pRelInfo ) +{ + ERRCODE uiError; + + if ( pArea->lpdbPendingRel == pRelInfo ) + uiError = SELF_FORCEREL( (AREAP) pArea ); + else + uiError = SUCCESS; + SUPER_CHILDEND( (AREAP) pArea, pRelInfo ); + return uiError; +} + + +static ERRCODE sqlbaseChildStart( SQLBASEAREAP pArea, LPDBRELINFO pRelInfo ) +{ + if ( SELF_CHILDSYNC( (AREAP) pArea, pRelInfo ) != SUCCESS ) + return FAILURE; + return SUPER_CHILDSTART( (AREAP) pArea, pRelInfo ); +} + + +static ERRCODE sqlbaseChildSync( SQLBASEAREAP pArea, LPDBRELINFO pRelInfo ) +{ + if ( SELF_GOCOLD( (AREAP) pArea ) != SUCCESS ) + return FAILURE; + + pArea->lpdbPendingRel = pRelInfo; + + if ( pArea->lpdbRelations ) + return SELF_SYNCCHILDREN( (AREAP) pArea ); + + return SUCCESS; +} + + +static ERRCODE sqlbaseForceRel( SQLBASEAREAP pArea ) +{ + if ( pArea->lpdbPendingRel ) + { + LPDBRELINFO lpdbPendingRel; + + lpdbPendingRel = pArea->lpdbPendingRel; + pArea->lpdbPendingRel = NULL; + return SELF_RELEVAL( (AREAP) pArea, lpdbPendingRel ); + } + return SUCCESS; +} + + +static ERRCODE sqlbaseSetFilter( SQLBASEAREAP pArea, LPDBFILTERINFO pFilterInfo ) +{ + if ( pArea->lpdbPendingRel ) + { + if ( SELF_FORCEREL( (AREAP) pArea ) != SUCCESS ) + return FAILURE; + } + return SUPER_SETFILTER( (AREAP) pArea, pFilterInfo ); +} +*/ + + +static ERRCODE sqlbaseExit( LPRDDNODE pRDD ) +{ + ULONG ul; + + HB_SYMBOL_UNUSED( pRDD ); + + if ( s_pConnection ) + { + // Disconnect all connections + for ( ul = 0; ul < s_ulConnectionCount; ul++ ) + { + if ( s_pConnection[ ul ].hConnection ) + { + s_pConnection[ ul ].pSDD->Disconnect( & s_pConnection[ ul ] ); + if ( s_pConnection[ ul ].szError ) + hb_xfree( s_pConnection[ ul ].szError ); + if ( s_pConnection[ ul ].szQuery ) + hb_xfree( s_pConnection[ ul ].szQuery ); + hb_itemRelease( s_pConnection[ ul ].pNewID ); + } + } + hb_xfree( s_pConnection ); + s_pConnection = NULL; + s_ulConnectionCount = 0; + s_ulConnectionCurrent = 0; + } + + return SUCCESS; +} + + +static ERRCODE sqlbaseRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ) +{ + ULONG ulConn; + SQLDDCONNECTION* pConn; + + HB_SYMBOL_UNUSED( pRDD ); + // TraceLog( NULL, "RDDINFO index: %d type:%04X\n", (int)uiIndex, pItem->type ); + + ulConn = ulConnect ? ulConnect : s_ulConnectionCurrent; + if ( ulConn > 0 && ulConn < s_ulConnectionCount && s_pConnection[ --ulConn ].hConnection ) + pConn = & s_pConnection[ ulConn ]; + else + pConn = NULL; + + switch( uiIndex ) + { + + case RDDI_REMOTE: + hb_itemPutL( pItem, TRUE ); + break; + + case RDDI_CONNECTION: + { + 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, FALSE ); + break; + + case RDDI_CANPUTREC: + hb_itemPutL( pItem, TRUE ); + break; + + + case RDDI_CONNECT: + { + PSDDNODE pNode = NULL; + ULONG ul; + char* pStr; + + // Find free connection handle + for ( ul = 0; ul < s_ulConnectionCount; ul++ ) + { + if ( ! s_pConnection[ ul ].hConnection ) + 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; + } + + pStr = hb_arrayGetCPtr( pItem, 1 ); + if ( pStr ) + { + pNode = s_pSdd; + while ( pNode ) + { + if ( ! hb_stricmp( pNode->Name, pStr ) ) + break; + pNode = pNode->pNext; + } + } + + pConn = & s_pConnection[ ul ]; + ul++; + if ( pNode && pNode->Connect( pConn, pItem ) == SUCCESS ) + { + pConn->pSDD = pNode; + pConn->pNewID = hb_itemNew( NULL ); + } + else + ul = 0; + + if ( ul ) + s_ulConnectionCurrent = ul; + + hb_itemPutNI( pItem, ul ); + break; + } + + case RDDI_DISCONNECT: + { + + if ( pConn && pConn->pSDD->Disconnect( pConn ) == SUCCESS ) + { + pConn->hConnection = 0; + pConn->iError = 0; + if ( pConn->szError ) + { + hb_xfree( pConn->szError ); + pConn->szError = NULL; + } + if ( pConn->szQuery ) + { + hb_xfree( pConn->szQuery ); + pConn->szQuery = NULL; + } + hb_itemRelease( pConn->pNewID ); + + hb_itemPutL( pItem, TRUE ); + return SUCCESS; + } + hb_itemPutL( pItem, FALSE ); + return SUCCESS; + } + + case RDDI_EXECUTE: + { + if ( pConn ) + { + hb_itemClear( pConn->pNewID ); + pConn->iError = 0; + if ( pConn->szError ) + { + hb_xfree( pConn->szError ); + pConn->szError = NULL; + } + if ( pConn->szQuery ) + { + hb_xfree( pConn->szQuery ); + pConn->szQuery = NULL; + } + pConn->szQuery = hb_strdup( hb_itemGetCPtr( pItem ) ); + + hb_itemPutL( pItem, pConn->pSDD->Execute( pConn, pItem ) == SUCCESS ); + } + else + hb_itemPutL( pItem, FALSE ); + + return SUCCESS; + } + + case RDDI_ERROR: + { + if ( pConn ) + hb_itemPutC( pItem, pConn->szError ); + else + hb_itemClear( pItem ); + return SUCCESS; + } + + case RDDI_ERRORNO: + { + if ( pConn ) + hb_itemPutNI( pItem, pConn->iError ); + else + hb_itemClear( pItem ); + return SUCCESS; + } + + case RDDI_QUERY: + { + if ( pConn ) + hb_itemPutC( pItem, pConn->szQuery ); + else + hb_itemClear( pItem ); + return SUCCESS; + } + + case RDDI_NEWID: + { + if ( pConn ) + hb_itemCopy( pItem, pConn->pNewID ); + else + hb_itemClear( pItem ); + return SUCCESS; + } + + case RDDI_AFFECTEDROWS: + { + if ( pConn ) + hb_itemPutNInt( pItem, pConn->ulAffectedRows ); + else + hb_itemClear( pItem ); + return SUCCESS; + } + +// default: +// return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem ); + + } + + return 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_SVP ) 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_P ) NULL, // sqlbaseAlias + ( DBENTRYP_V ) sqlbaseClose, + ( DBENTRYP_VP ) sqlbaseCreate, + ( DBENTRYP_SI ) sqlbaseInfo, + ( DBENTRYP_V ) NULL, // sqlbaseNewArea + ( DBENTRYP_VP ) sqlbaseOpen, + ( DBENTRYP_V ) NULL, // sqlbaseRelease + ( DBENTRYP_SP ) sqlbaseStructSize, + ( DBENTRYP_P ) 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 ) NULL, // 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_SVP ) NULL, // sqlbaseRelArea + ( DBENTRYP_VR ) NULL, // sqlbaseRelEval + ( DBENTRYP_SVP ) NULL, // sqlbaseRelText + ( DBENTRYP_VR ) NULL, // sqlbaseSetRel + ( DBENTRYP_OI ) NULL, // sqlbaseOrderListAdd + ( DBENTRYP_V ) NULL, // sqlbaseOrderListClear + ( DBENTRYP_OI ) NULL, // sqlbaseOrderListDelete + ( DBENTRYP_OI ) NULL, // sqlbaseOrderListFocus + ( DBENTRYP_V ) NULL, // sqlbaseOrderListRebuild + ( DBENTRYP_VOI ) NULL, // sqlbaseOrderCondition + ( DBENTRYP_VOC ) NULL, // sqlbaseOrderCreate + ( DBENTRYP_OI ) NULL, // sqlbaseOrderDestroy + ( DBENTRYP_OII ) 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_P ) 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_VP ) NULL, // sqlbaseCreateMemFile + ( DBENTRYP_SVPB ) NULL, // sqlbaseGetValueFile + ( DBENTRYP_VP ) NULL, // sqlbaseOpenMemFile + ( DBENTRYP_SVPB ) NULL, // sqlbasePutValueFile + ( DBENTRYP_V ) NULL, // sqlbaseReadDBHeader + ( DBENTRYP_V ) NULL, // sqlbaseWriteDBHeader + ( DBENTRYP_R ) NULL, // sqlbaseInit + ( DBENTRYP_R ) sqlbaseExit, + ( DBENTRYP_RVVL ) NULL, // sqlbaseDrop + ( DBENTRYP_RVVL ) NULL, // sqlbaseExists + ( DBENTRYP_RSLV ) sqlbaseRddInfo, + ( DBENTRYP_SVP ) NULL // sqlbaseWhoCares +}; + + +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 ); + } +} + + +#define __PRG_SOURCE__ __FILE__ + +#ifdef HB_PCODE_VER + #undef HB_PRG_PCODE_VER + #define HB_PRG_PCODE_VER HB_PCODE_VER +#endif + + +HB_FUNC( SQLBASE ) {;} + + +HB_FUNC( SQLBASE_GETFUNCTABLE ) +{ + RDDFUNCS * pTable; + USHORT * uiCount, uiRddId; + + uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) ); + * uiCount = RDDFUNCSCOUNT; + pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) ); + uiRddId = ( USHORT ) hb_parni( 4 ); + + if ( pTable ) + { + ERRCODE errCode; + + errCode = hb_rddInherit( pTable, &sqlbaseTable, &sqlbaseSuper, 0 ); + if ( errCode == SUCCESS ) + { + s_rddidSQLBASE = uiRddId; + } + hb_retni( errCode ); + } + else + { + hb_retni( FAILURE ); + } +} + + +HB_INIT_SYMBOLS_BEGIN( sqlbase1__InitSymbols ) +{ "SQLBASE", HB_FS_PUBLIC, HB_FUNCNAME( SQLBASE ), NULL }, +{ "SQLBASE_GETFUNCTABLE", HB_FS_PUBLIC, HB_FUNCNAME( SQLBASE_GETFUNCTABLE ), NULL } +HB_INIT_SYMBOLS_END( sqlbase1__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 sqlbase1__InitSymbols + #pragma startup _hb_sqlbase_init_ +#elif defined( HB_MSC_STARTUP ) + #if defined( HB_OS_WIN_64 ) + #pragma section( HB_MSC_START_SEGMENT, long, read ) + #endif + #pragma data_seg( HB_MSC_START_SEGMENT ) + static HB_$INITSYM hb_vm_auto_sqlbase1__InitSymbols = sqlbase1__InitSymbols; + static HB_$INITSYM hb_vm_auto_sqlbase_init = _hb_sqlbase_init_; + #pragma data_seg() +#endif diff --git a/harbour/contrib/rddsql/sqlmix.c b/harbour/contrib/rddsql/sqlmix.c new file mode 100644 index 0000000000..38a908b0ec --- /dev/null +++ b/harbour/contrib/rddsql/sqlmix.c @@ -0,0 +1,2350 @@ +/* + * $Id$ + */ + +/* + * SQL MIX (Memory Index) Database Driver + * + * Copyright 2007 Mindaugas Kavaliauskas + * 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. + * + */ + +#define HB_OS_WIN_32_USED + +#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 "hbsqldd.h" + +#include + +#define SUPERTABLE ( &sqlmixSuper ) + +//#define DEBUG + + +#define MIX_KEY( tag, node, index ) \ + ( (PMIXKEY) & ( (BYTE*) (node) ) [ ( (node)->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + (index) * (tag)->uiTotalLen ] ) + +#define MIX_COPY_KEYS_INTERNAL( tag, node, dst, src, count ) \ + memmove( ( (BYTE*) (node) ) + ( (node)->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + (dst) * (tag)->uiTotalLen, \ + ( (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( ( (BYTE*) (ndst) ) + ( (ndst)->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + (dst) * (tag)->uiTotalLen, \ + ( (BYTE*) (nsrc) ) + ( (nsrc)->Leaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + (src) * (tag)->uiTotalLen, \ + (count) * (tag)->uiTotalLen ) + +#define MIX_ASSIGN_KEY( tag, node, dst, src ) \ + memmove( ( (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 USHORT s_uiRddIdSQLMIX = ( USHORT ) -1; + +static RDDFUNCS sqlmixSuper; + + +//======================================================================= +// Misc functions +//======================================================================= + + +static ERRCODE sqlmixErrorRT( SQLMIXAREAP pArea, USHORT uiGenCode, USHORT uiSubCode, char* filename, USHORT uiOsCode, USHORT uiFlags ) +{ + PHB_ITEM pError; + ERRCODE iRet = FAILURE; + + if ( hb_vmRequestQuery() == 0 ) + { + pError = hb_errNew(); + hb_errPutGenCode( pError, uiGenCode ); + hb_errPutSubCode( pError, uiSubCode ); + hb_errPutOsCode( pError, uiOsCode ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( uiGenCode ) ); + if ( filename ) + hb_errPutFileName( pError, filename ); + if ( uiFlags ) + hb_errPutFlags( pError, uiFlags ); + iRet = SELF_ERROR( (AREAP) pArea, 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, ULONG ulRecNo, PMIXTAG pTag ) +{ + ULONG ul; + double dbl; + BYTE buf[ 8 ]; + + if ( ! pKey ) + pKey = hb_mixKeyNew( pTag ); + + pKey->rec = ulRecNo; + pKey->notnul = 1; + + // TODO: check valtype + switch ( pTag->bType ) + { + case 'C': + ul = hb_itemGetCLen( pItem ); + + if ( ul > (ULONG) pTag->uiKeyLen ) + ul = pTag->uiKeyLen; + + memcpy( pKey->val, hb_itemGetCPtr( pItem ), ul ); + + if ( ul < (ULONG) pTag->uiKeyLen ) + memset( pKey->val + ul, ' ', (ULONG) pTag->uiKeyLen - ul ); + + 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 ] = (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->cdPage ); + + if ( iCurrArea != pArea->uiArea ) + hb_rddSelectWorkAreaNumber( pArea->uiArea ); + else + iCurrArea = 0; + + pItem = hb_vmEvalBlockOrMacro( pTag->pKeyItem ); + + pKey = hb_mixKeyPutItem( pKey, pItem, pArea->ulRecNo, pTag ); + + if ( iCurrArea ) + hb_rddSelectWorkAreaNumber( iCurrArea ); + + hb_cdpSelect( pCodepage ); + + return pKey; +} + + +static BOOL hb_mixEvalCond( SQLMIXAREAP pArea, PHB_ITEM pCondItem ) +{ + int iCurrArea = 0; + BOOL fRet; + + if ( pArea ) + { + iCurrArea = hb_rddGetCurrentWorkAreaNumber(); + + if ( iCurrArea != pArea->uiArea ) + hb_rddSelectWorkAreaNumber( pArea->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_mixKeyCompareValue( PMIXTAG pTag, PMIXKEY pKey1, PMIXKEY pKey2, UINT uiLen ) +{ + BYTE* pSortTable = pTag->pSortTable; + UINT ui, 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 ( pSortTable ) + { + ui = 0; + while ( i == 0 && ui < uiSize ) + { + i = pSortTable[ pKey1->val[ ui ] ] - pSortTable[ pKey2->val[ ui ] ]; + ui++; + } + } + else + { + if ( uiSize > 0 ) + i = memcmp( pKey1->val, pKey2->val, uiSize ); + } + + if ( i == 0 ) + { + // This condition seems inverted, but + if ( pTag->uiKeyLen > uiLen ) + i = -1; + } + return i; +} + + +static int hb_mixKeyCompare( PMIXTAG pTag, PMIXKEY pKey1, PMIXKEY pKey2, UINT uiLen ) +{ + BYTE* pSortTable = pTag->pSortTable; + UINT ui, 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 ( pSortTable ) + { + ui = 0; + while ( i == 0 && ui < uiSize ) + { + i = pSortTable[ pKey1->val[ ui ] ] - pSortTable[ pKey2->val[ ui ] ]; + ui++; + } + } + else + { + if ( uiSize > 0 ) + i = memcmp( pKey1->val, pKey2->val, uiSize ); + } + + if ( i == 0 ) + { + if ( pKey2->rec == (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 ) + { +// printf(" KC %d %d %d ", pKey1->rec, pKey2->rec, -2 ); + return -2; + } +// printf(" KC %d %d %d ", pKey1->rec, pKey2->rec, 2 ); + return 2; + } + + if ( pKey1->rec < pKey2->rec ) + { +// printf(" KC %d %d %d ", pKey1->rec, pKey2->rec, -1 ); + return -1; + } + else if ( pKey1->rec > pKey2->rec ) + { +// printf(" KC %d %d %d ", pKey1->rec, pKey2->rec, 1 ); + return 1; + } +// printf(" KC %d %d %d ", pKey1->rec, pKey2->rec, 0 ); + return 0; +} + + +// -------------------------- Tag management ---------------------------- +// hb_mixTag*() + +static void hb_mixTagPrintNode( PMIXTAG pTag, PMIXNODE pNode, int iLevel ) +{ + UINT 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("%*d %*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 ); + } +} + + +static PMIXNODE hb_mixTagCreateNode( PMIXTAG pTag, BOOL fLeaf ) +{ + PMIXNODE pNode; + ULONG ulSize; + + ulSize = ( fLeaf ? sizeof( MIXNODELEAF ) : sizeof( MIXNODE ) ) + MIX_NODE_ORDER * pTag->uiTotalLen; + + pNode = (PMIXNODE) hb_xgrab( ulSize ); + memset( pNode, 0, ulSize ); + pNode->Leaf = fLeaf ? 1 : 0; + return pNode; +} + + +static UINT hb_mixTagNodeParentIndex( PMIXNODE pNode ) +{ + PMIXNODE pParent = pNode->Parent; + UINT ui; + + // Find position in the parent node + ui = pParent->KeyCount; + do { + if ( pParent->Child[ ui ] == pNode ) + return ui; + } while ( ui-- ); + + return (UINT) -1; +} + + +static int hb_mixTagFindKey( PMIXTAG pTag, PMIXKEY pKey, UINT uiLen, PMIXNODE* ppNode, UINT* puiPos, BOOL fValidKey ) +{ + PMIXNODE pNode; + UINT ui; + int i; + + pNode = pTag->Root; + + while ( 1 ) + { + 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, UINT uiPos ) +{ + if ( uiPos < pNode->KeyCount ) + { + pTag->CurNode = pNode; + pTag->CurPos = uiPos; + pTag->CurKey = MIX_KEY( pTag, pNode, uiPos ); + pTag->fEof = FALSE; + } + else + { + pTag->fEof = TRUE; + } +} + + +static BOOL hb_mixTagRefreshKey( PMIXTAG pTag ) +{ + SQLMIXAREAP pArea; + + pArea = pTag->pArea; + + if ( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if ( ! pArea->fPositioned ) + { + pTag->fEof = TRUE; + return FALSE; + } + else if ( pTag->fEof || pTag->CurKey->rec != pArea->ulRecNo ) + { + PMIXKEY pKey; + PMIXNODE pNode; + UINT ui; + + pKey = hb_mixKeyEval( NULL, pTag ); + + hb_mixTagFindKey( pTag, pKey, pTag->uiKeyLen, &pNode, &ui, FALSE ); + hb_mixTagSetCurrent( pTag, pNode, ui ); + + hb_mixKeyFree( pKey ); + return ! pTag->fEof && pTag->CurKey->rec == pArea->ulRecNo; + } + pTag->fBof = pTag->fEof = FALSE; + return TRUE; +} + + +static void hb_mixTagAddKeyNode( PMIXTAG pTag, PMIXNODE pNode, UINT 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, UINT uiPos, PMIXKEY pKey, PMIXNODE pChildLeft, PMIXNODE pChildRight ) +{ + PMIXNODE pNewNode; + UINT 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 ); + +// printf("--- uiPos=%d j=%d\n", uiPos, j); + if ( j > 0 && pNode->Parent->Child[ j - 1 ]->KeyCount < MIX_NODE_ORDER ) + { +// printf("+++ <\n"); + 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 ) + { +// printf("+++ >\n"); + // O gal cia reikia hb_mixTagAddKeyNode??? + 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 BOOL hb_mixTagAddKey( PMIXTAG pTag, PMIXKEY pKey ) +{ + PMIXNODE pNode; + UINT ui; + int i; + + i = hb_mixTagFindKey( pTag, pKey, pTag->uiKeyLen, &pNode, &ui, FALSE ); +// printf("hb_mixTagAddKey: ui=%d key=%p i=%d\n", ui, pKey, i); + + // Key can not be duplicated + if ( ! i ) + return FALSE; + + hb_mixTagAddKeyPos( pTag, pNode, ui, pKey, NULL, NULL ); + return TRUE; +} + + +static void hb_mixTagDelKeyNode( PMIXTAG pTag, PMIXNODE pNode, UINT uiPos ) +{ +// printf("hb_mixTagDelKeyNode node=%p pos=%d\n", pNode, 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 ) +{ + UINT i, j; + PMIXNODE pParent, pSibling; + + + while ( 1 ) + { + if ( pNode->KeyCount >= MIX_NODE_ORDER / 2 ) + return; + +// printf("bt_adjust cycle node=%p node->keycount=%d\n", pNode, pNode->KeyCount ); + + // 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 ]; + + // negali buti pNode->Child[ 0 ], jei tai nera 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, UINT uiPos ) +{ +// printf("hb_mixTagDelKeyPos node=%p pos=%d\n", pNode, 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 BOOL hb_mixTagDelKey( PMIXTAG pTag, PMIXKEY pKey ) +{ + PMIXNODE pNode; + UINT ui; + int i; + + i = hb_mixTagFindKey( pTag, pKey, pTag->uiKeyLen, &pNode, &ui, FALSE ); +// printf("delete node=%p ui=%d key=%p i=%d\n", pNode, ui, pKey, i); + + if ( i ) + return FALSE; + + hb_mixTagDelKeyPos( pTag, pNode, ui ); + return 1; +} + + +static BYTE* hb_mixBuildSortTable( PHB_CODEPAGE pCodepage ) +{ + BYTE* pSortTable; + BYTE* pChars; + int i, j; + BYTE c; + + pSortTable = (BYTE*) hb_xalloc( 256 ); + + if ( pCodepage && pCodepage->s_chars ) + { + pChars = pCodepage->s_chars; + + c = 0; + for ( i = 0; i < 256; i++ ) + { + for ( j = 0; j < 256; j++ ) + { + if ( pChars[ j ] == (BYTE) i ) + { + pSortTable[ j ] = c; + c++; + } + } + } + } + else + { + for ( i = 0; i < 256; i++ ) + pSortTable[ i ] = ( BYTE ) i; + } + return pSortTable; +} + + +static PMIXTAG hb_mixTagCreate( char* szTagName, PHB_ITEM pKeyExpr, PHB_ITEM pKeyItem, PHB_ITEM pForItem, PHB_ITEM pWhileItem, BYTE bType, UINT uiKeyLen, SQLMIXAREAP pArea ) +{ + PMIXTAG pTag; + PMIXKEY pKey = NULL; + LPDBORDERCONDINFO pOrdCondInfo = pArea->lpdbOrdCondInfo; + ULONG ulStartRec, ulNextCount = 0; + LONG lStep = 0; + PHB_ITEM pItem, pEvalItem = NULL; + +// printf("hb_mixTagCreate\n"); + + pTag = ( PMIXTAG ) hb_xgrab( sizeof( MIXTAG ) ); + memset( pTag, 0, 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 expresion + pTag->szForExpr = NULL; + + pTag->pKeyItem = pKeyItem; + pTag->pForItem = pForItem; + pTag->bType = bType; + pTag->uiKeyLen = uiKeyLen; + + // TODO: MIXKEY alignment + pTag->uiTotalLen = sizeof( MIXKEY ) + pTag->uiKeyLen; + + // Use national support + if ( bType == 'C' ) + pTag->pSortTable = pArea->pSortTable; + + pTag->Root = hb_mixTagCreateNode( pTag, 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->ulRecNo; + + if ( pArea->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( (AREAP) pArea, ulStartRec ); + } + else + { + SELF_GOTOP( (AREAP) pArea ); + } + + while ( ! pArea->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->ulRecNo, pTag ); + hb_mixTagAddKey( pTag, pKey ); + } + + if ( ulNextCount ) + { + ulNextCount--; + if ( !ulNextCount ) break; + } + if ( SELF_SKIPRAW( ( AREAP ) pArea, 1 ) == FAILURE ) + break; + } + if ( pKey ) + hb_mixKeyFree( pKey ); + + return pTag; +} + + +static void hb_mixTagDestroyNode( PMIXNODE pNode ) +{ + if ( ! pNode->Leaf ) + { + UINT 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 ); + } + + 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 = TRUE; + return; + } + pTag->fEof = 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 = TRUE; + return; + } + pTag->fEof = FALSE; + pTag->CurNode = pNode; + pTag->CurPos = pNode->KeyCount - 1; + pTag->CurKey = MIX_KEY( pTag, pTag->CurNode, pTag->CurPos ); +} + + +static void hb_mixTagSkip( PMIXTAG pTag, LONG lSkip ) +{ + PMIXNODE pNode, pNode2; + UINT 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 = FALSE; + while ( ! pTag->fEof && lSkip > 0 ) + { + if ( pNode->Leaf ) + { + if ( (LONG) (pNode->KeyCount - 1 - uiPos) >= lSkip ) + { + uiPos += lSkip; + lSkip = 0; + } + else if ( pNode->KeyCount - 1 > uiPos ) + { + lSkip -= (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 = TRUE; + } + } + } + else + { + pNode = pNode->Child[ uiPos + 1 ]; + while ( ! pNode->Leaf ) + { + pNode = pNode->Child[ 0 ]; + } + uiPos = 0; + lSkip--; + } + } + } + else if ( lSkip < 0 ) + { + lSkip = - lSkip; + +// if ( pTag->fEof ) skip(-1) nuo Eof apdorojamas sqlmixSkipRaw +// { +// hb_mixTagGoBottom( pTag ); +// lSkip--; +// pTag->fBof = pTag->fEof; +// } + pTag->fBof = pTag->fEof; + + while ( ! pTag->fBof && lSkip > 0 ) + { + if ( pNode->Leaf ) + { + if ( (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 = 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 ULONG hb_mixTagNodeKeyCount( PMIXNODE pNode ) +{ + ULONG ulKeyCount; + UINT ui; + + ulKeyCount = pNode->KeyCount; + if ( ! pNode->Leaf ) + { + for ( ui = 0; ui <= pNode->KeyCount; ui++ ) + ulKeyCount += hb_mixTagNodeKeyCount( pNode->Child[ ui ] ); + } + return ulKeyCount; +} + + +static BOOL hb_mixCheckRecordFilter( SQLMIXAREAP pArea, ULONG ulRecNo ) +{ + BOOL lResult = FALSE; + + if ( pArea->dbfi.itmCobExpr || hb_setGetDeleted() ) + { + if ( pArea->ulRecNo != ulRecNo || pArea->lpdbPendingRel ) + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + + if ( hb_setGetDeleted() ) + SUPER_DELETED( ( AREAP ) pArea, &lResult ); + + if ( !lResult && pArea->dbfi.itmCobExpr ) + { + PHB_ITEM pResult = hb_vmEvalBlock( pArea->dbfi.itmCobExpr ); + lResult = HB_IS_LOGICAL( pResult ) && !hb_itemGetL( pResult ); + } + } + return !lResult; +} + + +static ULONG hb_mixDBOIKeyCount( PMIXTAG pTag, BOOL fFilter ) +{ + ULONG ulKeyCount; + + if ( ! pTag ) + return 0; + + if ( fFilter && pTag->pArea->dbfi.fFilter ) + { + PMIXNODE pNode = pTag->CurNode; + UINT uiPos = pTag->CurPos; + ULONG ulRecNo = pTag->pArea->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( (AREAP) pTag->pArea, ulRecNo ); + + } + else + { + ulKeyCount = hb_mixTagNodeKeyCount( pTag->Root ); + } + return ulKeyCount; +} + + +static ULONG hb_mixDBOIKeyNo( PMIXTAG pTag, BOOL fFilter ) +{ + ULONG ulKeyCount; + + if ( ! pTag ) + return 0; + + if ( fFilter ) + ulKeyCount = 0; + else + { + PMIXNODE pNode = pTag->CurNode; + UINT 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 ERRCODE sqlmixGoBottom( SQLMIXAREAP pArea ) +{ + ERRCODE retval; + + if ( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( ! pArea->pTag ) + return SUPER_GOBOTTOM( ( AREAP ) pArea ); + + if ( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + hb_mixTagGoBottom( pArea->pTag ); + + pArea->fTop = FALSE; + pArea->fBottom = TRUE; + + retval = SELF_GOTO( ( AREAP ) pArea, pArea->pTag->CurKey ? pArea->pTag->CurKey->rec : 0 ); + if ( retval != FAILURE && pArea->fPositioned ) + retval = SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); + + return retval; +} + + +static ERRCODE sqlmixGoTop( SQLMIXAREAP pArea ) +{ + ERRCODE retval; + + if ( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( ! pArea->pTag ) + return SUPER_GOTOP( ( AREAP ) pArea ); + + if ( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + hb_mixTagGoTop( pArea->pTag ); + + pArea->fTop = TRUE; + pArea->fBottom = FALSE; + + retval = SELF_GOTO( ( AREAP ) pArea, pArea->pTag->CurKey ? pArea->pTag->CurKey->rec : 0 ); + if ( retval != FAILURE && pArea->fPositioned ) + retval = SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); + + return retval; +} + + +static ERRCODE sqlmixSeek( SQLMIXAREAP pArea, BOOL fSoftSeek, PHB_ITEM pItem, BOOL fFindLast ) +{ + if ( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( ! pArea->pTag ) + { + sqlmixErrorRT( pArea, EG_NOORDER, 1201, NULL, 0, EF_CANDEFAULT ); + return FAILURE; + } + else + { + PMIXKEY pKey; + ERRCODE retval = SUCCESS; + BOOL fEOF; + PMIXTAG pTag = pArea->pTag; + PMIXNODE pNode; + UINT uiKeyLen, ui; + + if ( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + pArea->fEof = FALSE; + + pKey = hb_mixKeyPutItem( NULL, pItem, fFindLast ? (ULONG) -1 : 0, pTag ); + + uiKeyLen = pTag->uiKeyLen; + if ( pTag->bType == 'C' ) + { + uiKeyLen = (UINT) hb_itemGetCLen( pItem ); + if ( uiKeyLen > pTag->uiKeyLen ) + uiKeyLen = pTag->uiKeyLen; + } + + hb_mixTagFindKey( pTag, pKey, uiKeyLen, &pNode, &ui, TRUE ); + hb_mixTagSetCurrent( pTag, pNode, ui ); + + if ( fFindLast ) + { + if ( pTag->fEof ) + hb_mixTagGoBottom( pTag ); + else + hb_mixTagSkip( pTag, -1 ); + + pArea->fFound = ! pTag->fEof && ( uiKeyLen == 0 || memcmp( pTag->CurKey->val, pKey->val, (ULONG) uiKeyLen ) == 0 ); + + if ( ! pArea->fFound ) + hb_mixTagSetCurrent( pTag, pNode, ui ); + } + else + { + pArea->fFound = ! pTag->fEof && ( uiKeyLen == 0 || memcmp( pTag->CurKey->val, pKey->val, (ULONG) uiKeyLen ) == 0 ); + } + + fEOF = pTag->fEof; + + if ( !fEOF ) + { + retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + if ( retval != FAILURE && pArea->fPositioned ) + { + retval = SELF_SKIPFILTER( ( AREAP ) pArea, fFindLast ? -1 : 1 ); + if ( retval != FAILURE && pArea->fPositioned ) + { + pArea->fFound = ( uiKeyLen == 0 || memcmp( pTag->CurKey->val, pKey->val, (ULONG) uiKeyLen ) == 0 ); + if ( ! pArea->fFound && ! fSoftSeek ) + fEOF = TRUE; + } + } + } + if ( retval != FAILURE && fEOF ) + { + retval = SELF_GOTO( ( AREAP ) pArea, 0 ); + } + pArea->fBof = FALSE; + + hb_mixKeyFree( pKey ); + return retval; + } +} + + +static ERRCODE sqlmixSkipRaw( SQLMIXAREAP pArea, LONG lToSkip ) +{ + PMIXTAG pTag = pArea->pTag; + BOOL fOut = FALSE; + + if ( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( ! pTag || lToSkip == 0 ) + return SUPER_SKIPRAW( ( AREAP ) pArea, lToSkip ); + + if ( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if ( ! hb_mixTagRefreshKey( pTag ) ) + { + if ( lToSkip > 0 || pArea->fPositioned ) + fOut = TRUE; + else + { + hb_mixTagGoBottom( pTag ); + fOut = pTag->fEof; + lToSkip++; + } + } + + if ( ! fOut ) + hb_mixTagSkip( pTag, lToSkip ); + + if ( SELF_GOTO( ( AREAP ) pArea, ( pTag->fEof || fOut ) ? 0 : pTag->CurKey->rec ) != SUCCESS ) + return FAILURE; + pArea->fEof = pTag->fEof; + pArea->fBof = pTag->fBof; + return SUCCESS; +} + + +static ERRCODE sqlmixGoCold( SQLMIXAREAP pArea ) +{ + BOOL fRecordChanged = pArea->fRecordChanged; + BOOL fAppend = pArea->fAppend; + + if ( SUPER_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if ( fRecordChanged && pArea->pTagList ) + { + PMIXTAG pTag; + PMIXKEY pKey = NULL; + BOOL fAdd, fDel; + LPDBRELINFO lpdbPendingRel; + + lpdbPendingRel = pArea->lpdbPendingRel; + pArea->lpdbPendingRel = NULL; + + pTag = pArea->pTagList; + while ( pTag ) + { + + if ( ! pTag->fCustom ) + { + pKey = hb_mixKeyEval( pKey, pTag ); + +// printf( "sqlmixGoCold NEWKEY:%s rec:%d\n", pKey->val, pKey->rec); + + if ( pTag->pForItem != NULL ) + fAdd = hb_mixEvalCond( pArea, pTag->pForItem ); + else + fAdd = TRUE; + + if ( fAppend ) + fDel = 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 ); + } + pTag = pTag->pNext; + } + + if ( pKey ) + hb_mixKeyFree( pKey ); + + pArea->lpdbPendingRel = lpdbPendingRel; + } + + return SUCCESS; +} + + +static ERRCODE sqlmixGoHot( SQLMIXAREAP pArea ) +{ + PMIXTAG pTag; + +// if ( pArea->fRecordChanged ) +// printf( "sqlmixGoHot: multiple marking buffer as hot." ); + + if ( SUPER_GOHOT( (AREAP) pArea ) == FAILURE ) + return 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 SUCCESS; +} + + +static ERRCODE sqlmixClose( SQLMIXAREAP pArea ) +{ + if ( SELF_GOCOLD( (AREAP) pArea ) == FAILURE ) + return FAILURE; + + if ( SUPER_CLOSE( (AREAP) pArea ) == FAILURE ) + return FAILURE; + + if ( SELF_ORDLSTCLEAR( (AREAP) pArea ) == FAILURE ) + return FAILURE; + + return SUCCESS; +} + + +static ERRCODE sqlmixStructSize( SQLMIXAREAP pArea, USHORT* StructSize ) +{ + HB_SYMBOL_UNUSED( pArea ); + + * StructSize = sizeof( SQLMIXAREA ); + return SUCCESS; +} + + +static ERRCODE sqlmixOrderListClear( SQLMIXAREAP pArea ) +{ + PMIXTAG pTag; + + while ( pArea->pTagList ) + { + pTag = pArea->pTagList; + pArea->pTagList = pTag->pNext; + hb_mixTagDestroy( pTag ); + } + pArea->pTag = NULL; + return SUCCESS; +} + + +static 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 ? SUCCESS : FAILURE; +} + + +static ERRCODE sqlmixOrderCreate( SQLMIXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) +{ + PMIXTAG pTagNew, pTag; + PHB_ITEM pKeyItem, pForItem = NULL, pWhileItem = NULL, pResult; + ULONG ulRecNo; + USHORT uiLen; + BYTE bType; + +// printf("sqlmixOrderCreate\n"); + + // Obtain key codeblock + if ( pOrderInfo->itmCobExpr ) + { + pKeyItem = hb_itemNew( pOrderInfo->itmCobExpr ); + } + else + { + if ( SELF_COMPILE( (AREAP) pArea, (BYTE*) hb_itemGetCPtr( pOrderInfo->abExpr ) ) == FAILURE ) + return FAILURE; + pKeyItem = pArea->valResult; + pArea->valResult = NULL; + } + + // Test key codeblock on EOF + ulRecNo = pArea->ulRecNo; + SELF_GOTO( (AREAP) pArea, 0 ); + if ( SELF_EVALBLOCK( (AREAP) pArea, pKeyItem ) == FAILURE ) + { + hb_vmDestroyBlockOrMacro( pKeyItem ); + SELF_GOTO( (AREAP) pArea, ulRecNo ); + return FAILURE; + } + + pResult = pArea->valResult; + pArea->valResult = NULL; + + switch ( hb_itemType( pResult ) ) + { + case HB_IT_STRING: + case HB_IT_STRING | HB_IT_MEMO: + bType = 'C'; + uiLen = (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( (AREAP) pArea, ulRecNo ); + sqlmixErrorRT( pArea, bType == 'U' ? EG_DATATYPE : EG_DATAWIDTH, 1026, NULL, 0, 0 ); + return FAILURE; + } + + if ( pArea->lpdbOrdCondInfo ) + { + // Obtain FOR codeblock + if ( pArea->lpdbOrdCondInfo->itmCobFor ) + { + pForItem = hb_itemNew( pArea->lpdbOrdCondInfo->itmCobFor ); + } + else if ( pArea->lpdbOrdCondInfo->abFor ) + { + if ( SELF_COMPILE( (AREAP) pArea, pArea->lpdbOrdCondInfo->abFor ) == FAILURE ) + { + hb_vmDestroyBlockOrMacro( pKeyItem ); + SELF_GOTO( (AREAP) pArea, ulRecNo ); + return FAILURE; + } + pForItem = pArea->valResult; + pArea->valResult = NULL; + } + + // Obtain WHILE codeblock + if ( pArea->lpdbOrdCondInfo->itmCobWhile ) + { + pWhileItem = hb_itemNew( pArea->lpdbOrdCondInfo->itmCobWhile ); + } + else if ( pArea->lpdbOrdCondInfo->abWhile ) + { + if ( SELF_COMPILE( (AREAP) pArea, pArea->lpdbOrdCondInfo->abWhile ) == FAILURE ) + { + hb_vmDestroyBlockOrMacro( pKeyItem ); + if ( pForItem ) + hb_vmDestroyBlockOrMacro( pForItem ); + SELF_GOTO( (AREAP) pArea, ulRecNo ); + return FAILURE; + } + pWhileItem = pArea->valResult; + pArea->valResult = NULL; + } + } + + // Test FOR codeblock on EOF + if ( pForItem ) + { + if ( SELF_EVALBLOCK( (AREAP) pArea, pForItem ) == FAILURE ) + { + hb_vmDestroyBlockOrMacro( pKeyItem ); + hb_vmDestroyBlockOrMacro( pForItem ); + if ( pWhileItem ) + hb_vmDestroyBlockOrMacro( pWhileItem ); + SELF_GOTO( (AREAP) pArea, ulRecNo ); + return FAILURE; + } + if ( hb_itemType( pArea->valResult ) != HB_IT_LOGICAL ) + { + hb_itemRelease( pArea->valResult ); + pArea->valResult = 0; + hb_vmDestroyBlockOrMacro( pKeyItem ); + hb_vmDestroyBlockOrMacro( pForItem ); + if ( pWhileItem ) + hb_vmDestroyBlockOrMacro( pWhileItem ); + SELF_GOTO( (AREAP) pArea, ulRecNo ); + sqlmixErrorRT( pArea, EG_DATATYPE, EDBF_INVALIDFOR, NULL, 0, 0 ); + return FAILURE; + } + hb_itemRelease( pArea->valResult ); + pArea->valResult = 0; + } + + // TODO: WHILE condition is not tested, like in DBFCDX. Why? Compatibility with Clipper? + + SELF_GOTO( (AREAP) pArea, ulRecNo ); + + pTagNew = hb_mixTagCreate( ( char * ) 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 SUCCESS; +} + + +static PHB_ITEM hb_itemNil( PHB_ITEM pItem ) +{ + if ( pItem ) + { + if ( HB_IS_COMPLEX( pItem ) ) + hb_itemClear( pItem ); + } + else + pItem = hb_itemNew( NULL ); + + return pItem; +} + + +static ERRCODE sqlmixOrderInfo( SQLMIXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pOrderInfo ) +{ + PMIXTAG pTag; + USHORT uiTag = 0; + + + switch( uiIndex ) + { + case DBOI_EVALSTEP: + pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, + pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->lStep : 0 ); + return SUCCESS; + + case DBOI_ORDERCOUNT: + pTag = pArea->pTagList; + while ( pTag ) + { + pTag = pTag->pNext; + uiTag++; + } + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag ); + return SUCCESS; + } + + + if ( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return 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 : "" ) ); + 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 ) + { + char* pForExpr = hb_itemGetCPtr( pOrderInfo->itmNewVal ); + + if ( SELF_COMPILE( (AREAP) pArea, (BYTE*) pForExpr ) == SUCCESS ) + { + PHB_ITEM pForItem = pArea->valResult; + + pArea->valResult = NULL; + if ( SELF_EVALBLOCK( (AREAP) pArea, pForItem ) == SUCCESS ) + { + if ( hb_itemType( pArea->valResult ) == HB_IT_LOGICAL ) + { + pTag->szForExpr = hb_strdup( pForExpr ); + pTag->pForItem = pForItem; + pForItem = NULL; + } + hb_itemRelease( pArea->valResult ); + pArea->valResult = NULL; + } + if ( pForItem ) + hb_vmDestroyBlockOrMacro( pForItem ); + } + } + } + break; + + case DBOI_EXPRESSION: + pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pTag ? pTag->szKeyExpr : "" ); + break; + + case DBOI_POSITION: + case DBOI_KEYNORAW: + if ( pOrderInfo->itmNewVal && HB_IS_NUMERIC( pOrderInfo->itmNewVal ) ) + { +// pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, +// hb_cdxDBOIKeyGoto( pArea, pTag, +// hb_itemGetNL( pOrderInfo->itmNewVal ), uiIndex == DBOI_POSITION ) == SUCCESS ); + } + 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; + +/* + case DBOI_FINDREC: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOIFindRec( pArea, pTag, + hb_itemGetNL( pOrderInfo->itmNewVal ), FALSE ) ); + break; + + case DBOI_FINDRECCONT: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOIFindRec( pArea, pTag, + hb_itemGetNL( pOrderInfo->itmNewVal ), TRUE ) ); + break; +*/ + case DBOI_NAME: + pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pTag ? pTag->szName : "" ); + break; + + case DBOI_NUMBER: + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag ); // kitaip + 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, 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, "" ); + 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; + +/* + case DBOI_KEYVAL: + hb_itemClear( pOrderInfo->itmResult ); + if ( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + if ( pTag && pArea->fPositioned ) + { + if ( pTag->CurKey->rec != pArea->ulRecNo ) + { + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxCurKeyRefresh( pArea, pTag ); + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + if ( pTag->CurKey->rec == pArea->ulRecNo ) + pOrderInfo->itmResult = hb_cdxKeyGetItem( pTag->CurKey, + pOrderInfo->itmResult, pTag, TRUE ); + } + break; + + case DBOI_CUSTOM: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? pTag->fCustom : FALSE ) ); + if ( pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) + && hb_itemGetL( pOrderInfo->itmNewVal ) ) + { + pTag->fCustom = TRUE; + } + break; + + case DBOI_KEYADD: + if ( ! pTag ) + { + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + } + else + { + if ( pTag->fCustom ) + { + if ( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if ( ! pArea->fPositioned || + ( pTag->pForItem && + ! hb_cdxEvalCond( pArea, pTag->pForItem, TRUE ) ) ) + { + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + } + else + { + LPCDXKEY pKey; + hb_cdxIndexLockWrite( pTag->pIndex ); + if ( pOrderInfo->itmNewVal && ! HB_IS_NIL( pOrderInfo->itmNewVal ) ) + pKey = hb_cdxKeyPutItem( NULL, pOrderInfo->itmNewVal, pArea->ulRecNo, pTag, TRUE, 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, FALSE ); + } + else + { + if ( pTag->Custom ) + { + if ( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if ( !pArea->fPositioned || + ( pTag->pForItem && + !hb_cdxEvalCond( pArea, pTag->pForItem, TRUE ) ) ) + { + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + } + else + { + LPCDXKEY pKey; + hb_cdxIndexLockWrite( pTag->pIndex ); + if ( pOrderInfo->itmNewVal && !HB_IS_NIL( pOrderInfo->itmNewVal ) ) + pKey = hb_cdxKeyPutItem( NULL, pOrderInfo->itmNewVal, pArea->ulRecNo, pTag, TRUE, 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; + +*/ + case DBOI_SHARED: + case DBOI_ISREADONLY: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, FALSE ); + break; + + default: + return SUPER_ORDINFO( ( AREAP ) pArea, uiIndex, pOrderInfo ); + + } + return SUCCESS; +} + + +static ERRCODE sqlmixExit( LPRDDNODE pRDD ) +{ + // This empty method is used to avoid duplicated sqlbase exit call + HB_SYMBOL_UNUSED( pRDD ); + return 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_SVP ) 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_P ) NULL, // sqlmixAlias + ( DBENTRYP_V ) sqlmixClose, + ( DBENTRYP_VP ) NULL, // sqlmixCreate + ( DBENTRYP_SI ) NULL, // sqlmixInfo + ( DBENTRYP_V ) NULL, // sqlmixNewArea + ( DBENTRYP_VP ) NULL, // sqlmixOpen + ( DBENTRYP_V ) NULL, // sqlmixRelease + ( DBENTRYP_SP ) sqlmixStructSize, + ( DBENTRYP_P ) 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_SVP ) NULL, // sqlmixRelArea + ( DBENTRYP_VR ) NULL, // sqlmixRelEval + ( DBENTRYP_SVP ) NULL, // sqlmixRelText + ( DBENTRYP_VR ) NULL, // sqlmixSetRel + ( DBENTRYP_OI ) NULL, // sqlmixOrderListAdd + ( DBENTRYP_V ) sqlmixOrderListClear, + ( DBENTRYP_OI ) NULL, // sqlmixOrderListDelete + ( DBENTRYP_OI ) sqlmixOrderListFocus, + ( DBENTRYP_V ) NULL, // sqlmixOrderListRebuild + ( DBENTRYP_VOI ) NULL, // sqlmixOrderCondition + ( DBENTRYP_VOC ) sqlmixOrderCreate, + ( DBENTRYP_OI ) NULL, // sqlmixOrderDestroy + ( DBENTRYP_OII ) 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_P ) 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_VP ) NULL, // sqlmixCreateMemFile + ( DBENTRYP_SVPB ) NULL, // sqlmixGetValueFile + ( DBENTRYP_VP ) NULL, // sqlmixOpenMemFile + ( DBENTRYP_SVPB ) NULL, // sqlmixPutValueFile + ( DBENTRYP_V ) NULL, // sqlmixReadDBHeader + ( DBENTRYP_V ) NULL, // sqlmixWriteDBHeader + ( DBENTRYP_R ) NULL, // sqlmixInit + ( DBENTRYP_R ) sqlmixExit, + ( DBENTRYP_RVVL) NULL, // sqlmixDrop + ( DBENTRYP_RVVL) NULL, // sqlmixExists + ( DBENTRYP_RSLV ) NULL, // sqlmixRddInfo + ( DBENTRYP_SVP ) NULL, // sqlmixWhoCares + }; + + +HB_FUNC( SQLMIX_GETFUNCTABLE ) +{ + RDDFUNCS * pTable; + USHORT * uiCount, uiRddId; + + uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) ); + * uiCount = RDDFUNCSCOUNT; + pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) ); + uiRddId = ( USHORT ) hb_parni( 4 ); + + if ( pTable ) + { + ERRCODE errCode; + + errCode = hb_rddInherit( pTable, &sqlmixTable, &sqlmixSuper, "SQLBASE" ); + if ( errCode == SUCCESS ) + { + s_uiRddIdSQLMIX = uiRddId; + } + hb_retni( errCode ); + } + else + { + hb_retni( FAILURE ); + } +} + + +HB_FUNC( SQLMIX ) { ; } + + +#define __PRG_SOURCE__ __FILE__ + +#ifdef HB_PCODE_VER + #undef HB_PRG_PCODE_VER + #define HB_PRG_PCODE_VER HB_PCODE_VER +#endif + + +HB_FUNC_EXTERN( SQLBASE ); + + +static void hb_sqlmixRddInit( void * cargo ) +{ + HB_SYMBOL_UNUSED( cargo ); + + if ( hb_rddRegister( "SQLMIX", RDT_FULL ) > 1 ) + { + // try different RDD registrer order + hb_rddRegister( "SQLBASE", RDT_FULL ); + + if ( hb_rddRegister( "SQLMIX", RDT_FULL ) > 1 ) + { + hb_errInternal( HB_EI_RDDINVALID, NULL, NULL, NULL ); + HB_FUNC_EXEC( SQLBASE ); // force SQLBASE linking + } + } +} + +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_MSC_STARTUP) +# if _MSC_VER >= 1010 +# pragma data_seg( ".CRT$XIY" ) +# pragma comment( linker, "/Merge:.CRT=.data" ) +# else +# pragma data_seg( "XIY" ) +# endif + static HB_$INITSYM hb_vm_auto_sqlmix__InitSymbols = sqlmix__InitSymbols; + static HB_$INITSYM hb_vm_auto_sqlmix_rdd_init = _hb_sqlmix_rdd_init_; +# pragma data_seg() +#endif diff --git a/harbour/contrib/rddsql/tests/bld_b32.bat b/harbour/contrib/rddsql/tests/bld_b32.bat new file mode 100644 index 0000000000..f00989f399 --- /dev/null +++ b/harbour/contrib/rddsql/tests/bld_b32.bat @@ -0,0 +1,14 @@ +@echo off +rem +rem $Id$ +rem + +if "%HB_BIN_INSTALL%" == "" set HB_BIN_INSTALL=..\..\..\bin +if "%HB_LIB_INSTALL%" == "" set HB_LIB_INSTALL=..\..\..\lib +if "%HB_INC_INSTALL%" == "" set HB_INC_INSTALL=..\..\..\include + +set HB_ARCHITECTURE=w32 +set HB_COMPILER=bcc32 +set HB_USER_LIBS=rddsql.lib + +call %HB_BIN_INSTALL%\hbmk.bat %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/harbour/contrib/rddsql/tests/bld_vc.bat b/harbour/contrib/rddsql/tests/bld_vc.bat new file mode 100644 index 0000000000..61d7829021 --- /dev/null +++ b/harbour/contrib/rddsql/tests/bld_vc.bat @@ -0,0 +1,14 @@ +@echo off +rem +rem $Id$ +rem + +if "%HB_BIN_INSTALL%" == "" set HB_BIN_INSTALL=..\..\..\bin +if "%HB_LIB_INSTALL%" == "" set HB_LIB_INSTALL=..\..\..\lib +if "%HB_INC_INSTALL%" == "" set HB_INC_INSTALL=..\..\..\include + +set HB_ARCHITECTURE=w32 +set HB_COMPILER=msvc +set HB_USER_LIBS=rddsql.lib + +call %HB_BIN_INSTALL%\hbmk.bat %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/harbour/contrib/rddsql/tests/test1.prg b/harbour/contrib/rddsql/tests/test1.prg new file mode 100644 index 0000000000..1c10d510f5 --- /dev/null +++ b/harbour/contrib/rddsql/tests/test1.prg @@ -0,0 +1,56 @@ +/* + * $Id$ + */ + +#include "dbinfo.ch" +#include "error.ch" + +#define DBI_QUERY 1001 + +#define RDDI_CONNECT 1001 +#define RDDI_DISCONNECT 1002 +#define RDDI_EXECUTE 1003 +#define RDDI_ERROR 1004 +#define RDDI_ERRORNO 1005 +#define RDDI_NEWID 1006 +#define RDDI_AFFECTEDROWS 1007 +#define RDDI_QUERY 1008 + + +REQUEST MYSQLDD, SQLMIX + +FIELD RESIDENTS + +PROC main() +LOCAL hConn + RDDSETDEFAULT("SQLMIX") + + AEVAL(RDDLIST(), {|X| QOUT(X)}) + + IF RDDINFO(RDDI_CONNECT, {"MYSQL", "localhost", "test",, "test"}) == 0 + ? "Unable connect to the server" + RETURN + ENDIF + + CreateTable() + + ? "Let's browse table (press any key)" + INKEY(0) + DBUSEAREA( .T.,, "SELECT * FROM country", "country" ) + Browse() + + ? "Let's browse table ordered by resident count (press any key)" + INKEY(0) + INDEX ON RESIDENTS TAG residents TO country + Browse() + + DBCLOSEALL() +RETURN + +STATIC PROC CreateTable() + ? RDDINFO(RDDI_EXECUTE, "DROP TABLE country") + ? RDDINFO(RDDI_EXECUTE, "CREATE TABLE country (CODE char(3), NAME char(50), RESIDENTS int(11))") + ? RDDINFO(RDDI_EXECUTE, "INSERT INTO country values ('LTU', 'Lithuania', 3369600), ('USA', 'United States of America', 305397000), ('POR', 'Portugal', 10617600), ('POL', 'Poland', 38115967), ('AUS', 'Australia', 21446187), ('FRA', 'France', 64473140), ('RUS', 'Russia', 141900000)") +RETURN + +PROC RDDSYS(); RETURN diff --git a/harbour/source/rtl/alert.prg b/harbour/source/rtl/alert.prg index 856c66973e..df3d3f877b 100644 --- a/harbour/source/rtl/alert.prg +++ b/harbour/source/rtl/alert.prg @@ -92,7 +92,7 @@ FUNCTION Alert( xMessage, aOptions, cColorNorm, nDelay ) CASE hb_isLogical( xMessage ) ; cMessage := iif( xMessage, ".T.", ".F." ) CASE hb_isObject( xMessage ) ; cMessage := xMessage:className + " Object" CASE hb_isSymbol( xMessage ) ; cMessage := "@" + xMessage:Name + "()" - CASE hb_isBlock( xMessage ) ; cMessage := "{|| ... }" + CASE hb_isBlock( xMessage ) ; cMessage := "{||...}" OTHERWISE ; cMessage := "NIL" ENDCASE diff --git a/harbour/source/rtl/valtoexp.prg b/harbour/source/rtl/valtoexp.prg index 7aae897725..77a880c093 100644 --- a/harbour/source/rtl/valtoexp.prg +++ b/harbour/source/rtl/valtoexp.prg @@ -123,7 +123,7 @@ FUNCTION hb_CStr( xVal ) CASE "S" RETURN "@" + xVal:name + "()" CASE "B" - RETURN "{|| ... }" + RETURN "{||...}" CASE "O" RETURN "{ " + xVal:className + " Object }" CASE "A" diff --git a/harbour/source/rtl/xhelp.c b/harbour/source/rtl/xhelp.c index cc772fe2e9..5a2e462049 100644 --- a/harbour/source/rtl/xhelp.c +++ b/harbour/source/rtl/xhelp.c @@ -63,7 +63,7 @@ HB_FUNC( __XHELP ) if( hb_dynsymIsFunction( s_pDynSym ) ) { - /* awhite: push the existing params after the dyn symbol */ + /* NOTE: push the existing params after the dyn symbol. [awhite] */ USHORT uiPCount = ( USHORT ) hb_pcount(); USHORT uiParam; @@ -71,7 +71,7 @@ HB_FUNC( __XHELP ) hb_vmPushDynSym( s_pDynSym ); hb_vmPushNil(); /* CA-Cl*pper respects references so hb_stackItemFromBase() is - * used insted of hb_param() [druzus] + * used instead of hb_param() [druzus] */ for( uiParam = 1; uiParam <= uiPCount; uiParam++ ) hb_vmPush( hb_stackItemFromBase( uiParam ) ); diff --git a/harbour/source/vm/harbinit.prg b/harbour/source/vm/harbinit.prg index 2a925e120e..f893e36611 100644 --- a/harbour/source/vm/harbinit.prg +++ b/harbour/source/vm/harbinit.prg @@ -52,7 +52,7 @@ #include "inkey.ch" -ANNOUNCE SysInit +ANNOUNCE SYSINIT /* NOTE: For complete compatibility */ PROCEDURE CLIPPER520() @@ -72,7 +72,7 @@ PROCEDURE CLIPPER530() * explicitly in VM initialization process before hb_vmDoInitFunctions() * and not depends on INIT clause. */ -PROCEDURE ClipInit +PROCEDURE ClipInit() MEMVAR GetList