From d3df5063f0ef53ad5cb4f1a33e38333eb27d38e6 Mon Sep 17 00:00:00 2001 From: michael Date: Tue, 11 Jun 2002 18:40:27 +0000 Subject: [PATCH] + Initial implementation --- fcl/db/odbc/Makefile | 1206 +++++++++++++++++++++++++++++++ fcl/db/odbc/Makefile.fpc | 28 + fcl/db/odbc/README | 181 +++++ fcl/db/odbc/fpodbc.pp | 1465 ++++++++++++++++++++++++++++++++++++++ fcl/db/odbc/testbcon.pp | 63 ++ fcl/db/odbc/testcon.pp | 19 + fcl/db/odbc/testdrcon.pp | 20 + fcl/db/odbc/testenv.pp | 45 ++ fcl/db/odbc/testfl.pp | 29 + fcl/db/odbc/testodbc.mdb | Bin 0 -> 81920 bytes fcl/db/odbc/testpa.pp | 33 + fcl/db/odbc/testpk.pp | 29 + fcl/db/odbc/testpr.pp | 29 + fcl/db/odbc/testsql.pp | 102 +++ fcl/db/odbc/testst.pp | 62 ++ fcl/db/odbc/testtl.pp | 31 + 16 files changed, 3342 insertions(+) create mode 100644 fcl/db/odbc/Makefile create mode 100644 fcl/db/odbc/Makefile.fpc create mode 100644 fcl/db/odbc/README create mode 100644 fcl/db/odbc/fpodbc.pp create mode 100644 fcl/db/odbc/testbcon.pp create mode 100644 fcl/db/odbc/testcon.pp create mode 100644 fcl/db/odbc/testdrcon.pp create mode 100644 fcl/db/odbc/testenv.pp create mode 100644 fcl/db/odbc/testfl.pp create mode 100644 fcl/db/odbc/testodbc.mdb create mode 100644 fcl/db/odbc/testpa.pp create mode 100644 fcl/db/odbc/testpk.pp create mode 100644 fcl/db/odbc/testpr.pp create mode 100644 fcl/db/odbc/testsql.pp create mode 100644 fcl/db/odbc/testst.pp create mode 100644 fcl/db/odbc/testtl.pp diff --git a/fcl/db/odbc/Makefile b/fcl/db/odbc/Makefile new file mode 100644 index 0000000000..9e4c7ccbba --- /dev/null +++ b/fcl/db/odbc/Makefile @@ -0,0 +1,1206 @@ +# +# Don't edit, this file is generated by FPCMake Version 1.1 [2002/03/28] +# +default: all +MAKEFILETARGETS=linux win32 +override PATH:=$(subst \,/,$(PATH)) +ifeq ($(findstring ;,$(PATH)),) +inUnix=1 +SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH))) +else +SEARCHPATH:=$(subst ;, ,$(PATH)) +endif +PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(SEARCHPATH)))) +ifeq ($(PWD),) +PWD:=$(strip $(wildcard $(addsuffix /pwd,$(SEARCHPATH)))) +ifeq ($(PWD),) +$(error You need the GNU utils package to use this Makefile) +else +PWD:=$(firstword $(PWD)) +SRCEXEEXT= +endif +else +PWD:=$(firstword $(PWD)) +SRCEXEEXT=.exe +endif +ifndef inUnix +ifeq ($(OS),Windows_NT) +inWinNT=1 +else +ifdef OS2_SHELL +inOS2=1 +endif +endif +else +ifneq ($(findstring cygwin,$(MACHTYPE)),) +inCygWin=1 +endif +endif +ifeq ($(OS_TARGET),freebsd) +BSDhier=1 +endif +ifeq ($(OS_TARGET),netbsd) +BSDhier=1 +endif +ifdef inUnix +BATCHEXT=.sh +else +ifdef inOS2 +BATCHEXT=.cmd +else +BATCHEXT=.bat +endif +endif +ifdef inUnix +PATHSEP=/ +else +PATHSEP:=$(subst /,\,/) +endif +ifdef PWD +BASEDIR:=$(subst \,/,$(shell $(PWD))) +ifdef inCygWin +ifneq ($(findstring /cygdrive/,$(BASEDIR)),) +BASENODIR:=$(patsubst /cygdrive%,%,$(BASEDIR)) +BASEDRIVE:=$(firstword $(subst /, ,$(BASENODIR))) +BASEDIR:=$(subst /cygdrive/$(BASEDRIVE)/,$(BASEDRIVE):/,$(BASEDIR)) +endif +endif +else +BASEDIR=. +endif +ifdef inOS2 +ifndef ECHO +ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO=echo +else +ECHO:=$(firstword $(ECHO)) +endif +else +ECHO:=$(firstword $(ECHO)) +endif +endif +export ECHO +endif +override DEFAULT_FPCDIR=../../.. +ifndef FPC +ifdef PP +FPC=$(PP) +endif +endif +ifndef FPC +FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH)))) +ifneq ($(FPCPROG),) +FPCPROG:=$(firstword $(FPCPROG)) +FPC:=$(shell $(FPCPROG) -PB) +ifneq ($(findstring Error,$(FPC)),) +override FPC=ppc386 +endif +else +override FPC=ppc386 +endif +endif +override FPC:=$(subst $(SRCEXEEXT),,$(FPC)) +override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT) +ifndef FPC_VERSION +FPC_VERSION:=$(shell $(FPC) -iV) +endif +export FPC FPC_VERSION +unexport CHECKDEPEND ALLDEPENDENCIES +ifeq ($(findstring 1.0.,$(FPC_VERSION)),) +COMPILERINFO:=$(shell $(FPC) -iSP -iTP -iSO -iTO) +ifndef CPU_SOURCE +CPU_SOURCE:=$(word 1,$(COMPILERINFO)) +endif +ifndef CPU_TARGET +CPU_TARGET:=$(word 2,$(COMPILERINFO)) +endif +ifndef OS_SOURCE +OS_SOURCE:=$(word 3,$(COMPILERINFO)) +endif +ifndef OS_TARGET +OS_TARGET:=$(word 4,$(COMPILERINFO)) +endif +else +ifndef CPU_SOURCE +CPU_SOURCE:=$(shell $(FPC) -iSP) +endif +ifndef CPU_TARGET +CPU_TARGET:=$(shell $(FPC) -iTP) +endif +ifndef OS_SOURCE +OS_SOURCE:=$(shell $(FPC) -iSO) +endif +ifndef OS_TARGET +OS_TARGET:=$(shell $(FPC) -iTO) +endif +endif +FULL_TARGET=$(CPU_TARGET)-$(OS_TARGET) +FULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE) +ifneq ($(FULL_TARGET),$(FULL_SOURCE)) +CROSSCOMPILE=1 +endif +ifeq ($(findstring makefile,$(MAKECMDGOALS)),) +ifeq ($(findstring $(OS_TARGET),$(MAKEFILETARGETS)),) +$(error The Makefile doesn't support target $(OS_TARGET), please run fpcmake first) +endif +endif +export OS_TARGET OS_SOURCE CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE CROSSCOMPILE +ifdef FPCDIR +override FPCDIR:=$(subst \,/,$(FPCDIR)) +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),) +override FPCDIR=wrong +endif +else +override FPCDIR=wrong +endif +ifdef DEFAULT_FPCDIR +ifeq ($(FPCDIR),wrong) +override FPCDIR:=$(subst \,/,$(DEFAULT_FPCDIR)) +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),) +override FPCDIR=wrong +endif +endif +endif +ifeq ($(FPCDIR),wrong) +ifdef inUnix +override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION) +ifeq ($(wildcard $(FPCDIR)/units),) +override FPCDIR=/usr/lib/fpc/$(FPC_VERSION) +endif +else +override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH)))))) +override FPCDIR:=$(FPCDIR)/.. +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),) +override FPCDIR:=$(FPCDIR)/.. +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),) +override FPCDIR=c:/pp +endif +endif +endif +endif +ifndef CROSSDIR +CROSSDIR:=$(FPCDIR)/cross/$(FULL_TARGET) +endif +ifndef CROSSTARGETDIR +CROSSTARGETDIR=$(CROSSDIR)/$(FULL_TARGET) +endif +ifdef CROSSCOMPILE +UNITSDIR:=$(wildcard $(CROSSTARGETDIR)/units) +ifeq ($(UNITSDIR),) +UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET)) +endif +else +UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET)) +endif +PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages/base $(FPCDIR)/packages/extra) +override PACKAGE_NAME=fcl +override TARGET_UNITS+=fpodbc +override TARGET_EXAMPLES+=testbcon testcon testdrcon testenv testfl testpa testpktestpr testsql testst testtl +override INSTALL_FPCPACKAGE=y +override COMPILER_OPTIONS+=-S2 +override COMPILER_TARGETDIR+=../../$(OS_TARGET) +ifdef REQUIRE_UNITSDIR +override UNITSDIR+=$(REQUIRE_UNITSDIR) +endif +ifdef REQUIRE_PACKAGESDIR +override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR) +endif +ifdef ZIPINSTALL +ifeq ($(OS_TARGET),linux) +UNIXINSTALLDIR=1 +endif +ifeq ($(OS_TARGET),freebsd) +UNIXINSTALLDIR=1 +endif +ifeq ($(OS_TARGET),netbsd) +UNIXINSTALLDIR=1 +endif +ifeq ($(OS_TARGET),sunos) +UNIXINSTALLDIR=1 +endif +else +ifeq ($(OS_SOURCE),linux) +UNIXINSTALLDIR=1 +endif +ifeq ($(OS_SOURCE),freebsd) +UNIXINSTALLDIR=1 +endif +ifeq ($(OS_SOURCE),netbsd) +UNIXINSTALLDIR=1 +endif +ifeq ($(OS_TARGET),sunos) +UNIXINSTALLDIR=1 +endif +endif +ifndef INSTALL_PREFIX +ifdef PREFIX +INSTALL_PREFIX=$(PREFIX) +endif +endif +ifndef INSTALL_PREFIX +ifdef UNIXINSTALLDIR +INSTALL_PREFIX=/usr/local +else +ifdef INSTALL_FPCPACKAGE +INSTALL_BASEDIR:=/pp +else +INSTALL_BASEDIR:=/$(PACKAGE_NAME) +endif +endif +endif +export INSTALL_PREFIX +ifdef INSTALL_FPCSUBDIR +export INSTALL_FPCSUBDIR +endif +ifndef DIST_DESTDIR +DIST_DESTDIR:=$(BASEDIR) +endif +export DIST_DESTDIR +ifndef INSTALL_BASEDIR +ifdef UNIXINSTALLDIR +ifdef INSTALL_FPCPACKAGE +INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/fpc/$(FPC_VERSION) +else +INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/$(PACKAGE_NAME) +endif +else +INSTALL_BASEDIR:=$(INSTALL_PREFIX) +endif +endif +ifndef INSTALL_BINDIR +ifdef UNIXINSTALLDIR +INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin +else +INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin +ifdef INSTALL_FPCPACKAGE +INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(OS_TARGET) +endif +endif +endif +ifndef INSTALL_UNITDIR +ifdef CROSSCOMPILE +INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/cross/$(FULL_TARGET)/units +else +INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(OS_TARGET) +endif +ifdef INSTALL_FPCPACKAGE +ifdef PACKAGE_NAME +INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME) +endif +endif +endif +ifndef INSTALL_LIBDIR +ifdef UNIXINSTALLDIR +INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib +else +INSTALL_LIBDIR:=$(INSTALL_UNITDIR) +endif +endif +ifndef INSTALL_SOURCEDIR +ifdef UNIXINSTALLDIR +ifdef BSDhier +SRCPREFIXDIR=share/src +else +SRCPREFIXDIR=src +endif +ifdef INSTALL_FPCPACKAGE +ifdef INSTALL_FPCSUBDIR +INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME) +else +INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME) +endif +else +INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +endif +else +ifdef INSTALL_FPCPACKAGE +ifdef INSTALL_FPCSUBDIR +INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME) +else +INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(PACKAGE_NAME) +endif +else +INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source +endif +endif +endif +ifndef INSTALL_DOCDIR +ifdef UNIXINSTALLDIR +ifdef BSDhier +DOCPREFIXDIR=share/doc +else +DOCPREFIXDIR=doc +endif +ifdef INSTALL_FPCPACKAGE +INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME) +else +INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +endif +else +ifdef INSTALL_FPCPACKAGE +INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc/$(PACKAGE_NAME) +else +INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc +endif +endif +endif +ifndef INSTALL_EXAMPLEDIR +ifdef UNIXINSTALLDIR +ifdef INSTALL_FPCPACKAGE +ifdef BSDhier +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME) +else +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME) +endif +else +ifdef BSDhier +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +else +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +endif +endif +else +ifdef INSTALL_FPCPACKAGE +INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples/$(PACKAGE_NAME) +else +INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples +endif +endif +endif +ifndef INSTALL_DATADIR +INSTALL_DATADIR=$(INSTALL_BASEDIR) +endif +ifdef CROSSCOMPILE +ifndef CROSSBINDIR +CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(FULL_SOURCE)) +ifeq ($(CROSSBINDIR),) +CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(FULL_TARGET)/bin/$(FULL_SOURCE)) +endif +endif +else +CROSSBINDIR= +endif +ifdef inUnix +ifndef GCCLIBDIR +GCCLIBDIR:=$(shell dirname `(gcc -v 2>&1)| head -n 1| awk '{ print $$4 } '`) +endif +ifeq ($(OS_TARGET),linux) +ifndef OTHERLIBDIR +OTHERLIBDIR:=$(shell grep -v "^\#" /etc/ld.so.conf | awk '{ ORS=" "; print $1 }') +endif +endif +ifeq ($(OS_TARGET),netbsd) +OTHERLIBDIR+=/usr/pkg/lib +endif +export GCCLIBDIR OTHERLIB +endif +LOADEREXT=.as +EXEEXT=.exe +PPLEXT=.ppl +PPUEXT=.ppu +OEXT=.o +ASMEXT=.s +SMARTEXT=.sl +STATICLIBEXT=.a +SHAREDLIBEXT=.so +STATICLIBPREFIX=libp +RSTEXT=.rst +FPCMADE=fpcmade +ifeq ($(OS_TARGET),go32v1) +PPUEXT=.pp1 +OEXT=.o1 +ASMEXT=.s1 +SMARTEXT=.sl1 +STATICLIBEXT=.a1 +SHAREDLIBEXT=.so1 +STATICLIBPREFIX= +FPCMADE=fpcmade.v1 +PACKAGESUFFIX=v1 +endif +ifeq ($(OS_TARGET),go32v2) +STATICLIBPREFIX= +FPCMADE=fpcmade.dos +ZIPSUFFIX=go32 +endif +ifeq ($(OS_TARGET),linux) +EXEEXT= +HASSHAREDLIB=1 +FPCMADE=fpcmade.lnx +ZIPSUFFIX=linux +endif +ifeq ($(OS_TARGET),freebsd) +EXEEXT= +HASSHAREDLIB=1 +FPCMADE=fpcmade.freebsd +ZIPSUFFIX=freebsd +endif +ifeq ($(OS_TARGET),netbsd) +EXEEXT= +HASSHAREDLIB=1 +FPCMADE=fpcmade.netbsd +ZIPSUFFIX=netbsd +endif +ifeq ($(OS_TARGET),win32) +PPUEXT=.ppw +OEXT=.ow +ASMEXT=.sw +SMARTEXT=.slw +STATICLIBEXT=.aw +SHAREDLIBEXT=.dll +FPCMADE=fpcmade.w32 +ZIPSUFFIX=w32 +endif +ifeq ($(OS_TARGET),os2) +PPUEXT=.ppo +ASMEXT=.so2 +OEXT=.oo2 +AOUTEXT=.out +SMARTEXT=.sl2 +STATICLIBPREFIX= +STATICLIBEXT=.ao2 +SHAREDLIBEXT=.dll +FPCMADE=fpcmade.os2 +ZIPSUFFIX=emx +ECHO=echo +endif +ifeq ($(OS_TARGET),amiga) +EXEEXT= +PPUEXT=.ppa +ASMEXT=.asm +OEXT=.o +SMARTEXT=.sl +STATICLIBEXT=.a +SHAREDLIBEXT=.library +FPCMADE=fpcmade.amg +endif +ifeq ($(OS_TARGET),atari) +PPUEXT=.ppt +ASMEXT=.s +OEXT=.o +SMARTEXT=.sl +STATICLIBEXT=.a +EXEEXT=.ttp +FPCMADE=fpcmade.ata +endif +ifeq ($(OS_TARGET),beos) +PPUEXT=.ppu +ASMEXT=.s +OEXT=.o +SMARTEXT=.sl +STATICLIBEXT=.a +EXEEXT= +FPCMADE=fpcmade.be +ZIPSUFFIX=be +endif +ifeq ($(OS_TARGET),sunos) +PPUEXT=.ppu +ASMEXT=.s +OEXT=.o +SMARTEXT=.sl +STATICLIBEXT=.a +EXEEXT= +FPCMADE=fpcmade.sun +ZIPSUFFIX=sun +endif +ifeq ($(OS_TARGET),qnx) +PPUEXT=.ppu +ASMEXT=.s +OEXT=.o +SMARTEXT=.sl +STATICLIBEXT=.a +EXEEXT= +FPCMADE=fpcmade.qnx +ZIPSUFFIX=qnx +endif +ifndef ECHO +ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO= +else +ECHO:=$(firstword $(ECHO)) +endif +else +ECHO:=$(firstword $(ECHO)) +endif +endif +export ECHO +ifndef DATE +DATE:=$(strip $(wildcard $(addsuffix /gdate$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(DATE),) +DATE:=$(strip $(wildcard $(addsuffix /date$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(DATE),) +DATE= +else +DATE:=$(firstword $(DATE)) +endif +else +DATE:=$(firstword $(DATE)) +endif +endif +export DATE +ifndef GINSTALL +GINSTALL:=$(strip $(wildcard $(addsuffix /ginstall$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(GINSTALL),) +GINSTALL:=$(strip $(wildcard $(addsuffix /install$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(GINSTALL),) +GINSTALL= +else +GINSTALL:=$(firstword $(GINSTALL)) +endif +else +GINSTALL:=$(firstword $(GINSTALL)) +endif +endif +export GINSTALL +ifndef CPPROG +CPPROG:=$(strip $(wildcard $(addsuffix /cp$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(CPPROG),) +CPPROG= +else +CPPROG:=$(firstword $(CPPROG)) +endif +endif +export CPPROG +ifndef RMPROG +RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(RMPROG),) +RMPROG= +else +RMPROG:=$(firstword $(RMPROG)) +endif +endif +export RMPROG +ifndef MVPROG +MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(MVPROG),) +MVPROG= +else +MVPROG:=$(firstword $(MVPROG)) +endif +endif +export MVPROG +ifndef ECHOREDIR +ECHOREDIR:=$(subst /,$(PATHSEP),$(ECHO)) +endif +ifndef COPY +COPY:=$(CPPROG) -fp +endif +ifndef COPYTREE +COPYTREE:=$(CPPROG) -rfp +endif +ifndef MOVE +MOVE:=$(MVPROG) -f +endif +ifndef DEL +DEL:=$(RMPROG) -f +endif +ifndef DELTREE +DELTREE:=$(RMPROG) -rf +endif +ifndef INSTALL +ifdef inUnix +INSTALL:=$(GINSTALL) -c -m 644 +else +INSTALL:=$(COPY) +endif +endif +ifndef INSTALLEXE +ifdef inUnix +INSTALLEXE:=$(GINSTALL) -c -m 755 +else +INSTALLEXE:=$(COPY) +endif +endif +ifndef MKDIR +MKDIR:=$(GINSTALL) -m 755 -d +endif +export ECHOREDIR COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR +ifndef PPUMOVE +PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(PPUMOVE),) +PPUMOVE= +else +PPUMOVE:=$(firstword $(PPUMOVE)) +endif +endif +export PPUMOVE +ifndef FPCMAKE +FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(FPCMAKE),) +FPCMAKE= +else +FPCMAKE:=$(firstword $(FPCMAKE)) +endif +endif +export FPCMAKE +ifndef ZIPPROG +ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ZIPPROG),) +ZIPPROG= +else +ZIPPROG:=$(firstword $(ZIPPROG)) +endif +endif +export ZIPPROG +ifndef TARPROG +TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(TARPROG),) +TARPROG= +else +TARPROG:=$(firstword $(TARPROG)) +endif +endif +export TARPROG +ASNAME=as +LDNAME=ld +ARNAME=ar +RCNAME=rc +ifeq ($(OS_TARGET),win32) +ASNAME=asw +LDNAME=ldw +ARNAME=arw +endif +ifndef ASPROG +ifdef CROSSBINDIR +ASPROG=$(CROSSBINDIR)/$(ASNAME)$(SRCEXEEXT) +else +ASPROG=$(ASNAME) +endif +endif +ifndef LDPROG +ifdef CROSSBINDIR +LDPROG=$(CROSSBINDIR)/$(LDNAME)$(SRCEXEEXT) +else +LDPROG=$(LDNAME) +endif +endif +ifndef RCPROG +ifdef CROSSBINDIR +RCPROG=$(CROSSBINDIR)/$(RCNAME)$(SRCEXEEXT) +else +RCPROG=$(RCNAME) +endif +endif +ifndef ARPROG +ifdef CROSSBINDIR +ARPROG=$(CROSSBINDIR)/$(ARNAME)$(SRCEXEEXT) +else +ARPROG=$(ARNAME) +endif +endif +AS=$(ASPROG) +LD=$(LDPROG) +RC=$(RCPROG) +AR=$(ARPROG) +PPAS=ppas$(BATCHEXT) +ifdef inUnix +LDCONFIG=ldconfig +else +LDCONFIG= +endif +ifdef DATE +DATESTR:=$(shell $(DATE) +%Y%m%d) +else +DATESTR= +endif +ifndef UPXPROG +ifeq ($(OS_TARGET),go32v2) +UPXPROG:=1 +endif +ifeq ($(OS_TARGET),win32) +UPXPROG:=1 +endif +ifdef UPXPROG +UPXPROG:=$(strip $(wildcard $(addsuffix /upx$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(UPXPROG),) +UPXPROG= +else +UPXPROG:=$(firstword $(UPXPROG)) +endif +else +UPXPROG= +endif +endif +export UPXPROG +ZIPOPT=-9 +ZIPEXT=.zip +ifeq ($(USETAR),bz2) +TAROPT=vI +TAREXT=.tar.bz2 +else +TAROPT=vz +TAREXT=.tar.gz +endif +override REQUIRE_PACKAGES=rtl odbc +ifeq ($(OS_TARGET),linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_ODBC=1 +endif +ifeq ($(OS_TARGET),win32) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_ODBC=1 +endif +ifdef REQUIRE_PACKAGES_RTL +PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/$(OS_TARGET)/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_RTL),) +ifneq ($(wildcard $(PACKAGEDIR_RTL)/$(OS_TARGET)),) +UNITDIR_RTL=$(PACKAGEDIR_RTL)/$(OS_TARGET) +else +UNITDIR_RTL=$(PACKAGEDIR_RTL) +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_RTL)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_RTL) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_RTL)/$(FPCMADE) +endif +else +PACKAGEDIR_RTL= +UNITDIR_RTL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /rtl/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_RTL),) +UNITDIR_RTL:=$(firstword $(UNITDIR_RTL)) +else +UNITDIR_RTL= +endif +endif +ifdef UNITDIR_RTL +override COMPILER_UNITDIR+=$(UNITDIR_RTL) +endif +endif +ifdef REQUIRE_PACKAGES_ODBC +PACKAGEDIR_ODBC:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /odbc/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_ODBC),) +ifneq ($(wildcard $(PACKAGEDIR_ODBC)/$(OS_TARGET)),) +UNITDIR_ODBC=$(PACKAGEDIR_ODBC)/$(OS_TARGET) +else +UNITDIR_ODBC=$(PACKAGEDIR_ODBC) +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_ODBC)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_ODBC) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_ODBC)/$(FPCMADE) +endif +else +PACKAGEDIR_ODBC= +UNITDIR_ODBC:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /odbc/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_ODBC),) +UNITDIR_ODBC:=$(firstword $(UNITDIR_ODBC)) +else +UNITDIR_ODBC= +endif +endif +ifdef UNITDIR_ODBC +override COMPILER_UNITDIR+=$(UNITDIR_ODBC) +endif +endif +ifndef NOCPUDEF +override FPCOPTDEF=$(CPU_TARGET) +endif +ifneq ($(OS_TARGET),$(OS_SOURCE)) +override FPCOPT+=-T$(OS_TARGET) +endif +ifdef UNITDIR +override FPCOPT+=$(addprefix -Fu,$(UNITDIR)) +endif +ifdef LIBDIR +override FPCOPT+=$(addprefix -Fl,$(LIBDIR)) +endif +ifdef OBJDIR +override FPCOPT+=$(addprefix -Fo,$(OBJDIR)) +endif +ifdef INCDIR +override FPCOPT+=$(addprefix -Fi,$(INCDIR)) +endif +ifdef LINKSMART +override FPCOPT+=-XX +endif +ifdef CREATESMART +override FPCOPT+=-CX +endif +ifdef DEBUG +override FPCOPT+=-gl +override FPCOPTDEF+=DEBUG +endif +ifdef RELEASE +ifeq ($(CPU_TARGET),i386) +FPCCPUOPT:=-OG2p3 +else +FPCCPUOPT:= +endif +override FPCOPT+=-Xs $(FPCCPUOPT) -n +override FPCOPTDEF+=RELEASE +endif +ifdef STRIP +override FPCOPT+=-Xs +endif +ifdef OPTIMIZE +ifeq ($(CPU_TARGET),i386) +override FPCOPT+=-OG2p3 +endif +endif +ifdef VERBOSE +override FPCOPT+=-vwni +endif +ifdef COMPILER_OPTIONS +override FPCOPT+=$(COMPILER_OPTIONS) +endif +ifdef COMPILER_UNITDIR +override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR)) +endif +ifdef COMPILER_LIBRARYDIR +override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR)) +endif +ifdef COMPILER_OBJECTDIR +override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR)) +endif +ifdef COMPILER_INCLUDEDIR +override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR)) +endif +ifdef CROSSBINDIR +override FPCOPT+=-FD$(CROSSBINDIR) +endif +ifdef COMPILER_TARGETDIR +override FPCOPT+=-FE$(COMPILER_TARGETDIR) +ifeq ($(COMPILER_TARGETDIR),.) +override TARGETDIRPREFIX= +else +override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/ +endif +endif +ifdef COMPILER_UNITTARGETDIR +override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR) +ifeq ($(COMPILER_UNITTARGETDIR),.) +override UNITTARGETDIRPREFIX= +else +override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/ +endif +else +ifdef COMPILER_TARGETDIR +override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR) +override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX) +endif +endif +ifdef GCCLIBDIR +override FPCOPT+=-Fl$(GCCLIBDIR) +endif +ifdef OTHERLIBDIR +override FPCOPT+=$(addprefix -Fl,$(OTHERLIBDIR)) +endif +ifdef OPT +override FPCOPT+=$(OPT) +endif +ifdef FPCOPTDEF +override FPCOPT+=$(addprefix -d,$(FPCOPTDEF)) +endif +ifdef CFGFILE +override FPCOPT+=@$(CFGFILE) +endif +ifdef USEENV +override FPCEXTCMD:=$(FPCOPT) +override FPCOPT:=!FPCEXTCMD +export FPCEXTCMD +endif +override COMPILER:=$(FPC) $(FPCOPT) +ifeq (,$(findstring -s ,$(COMPILER))) +EXECPPAS= +else +ifeq ($(OS_SOURCE),$(OS_TARGET)) +EXECPPAS:=@$(PPAS) +endif +endif +.PHONY: fpc_units +ifdef TARGET_UNITS +override ALLTARGET+=fpc_units +override UNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_UNITS)) +override IMPLICITUNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_IMPLICITUNITS)) +override INSTALLPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES) +override CLEANPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES) +endif +fpc_units: $(UNITPPUFILES) +ifdef TARGET_RSTS +override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS)) +override CLEANRSTFILES+=$(RSTFILES) +endif +.PHONY: fpc_examples +ifdef TARGET_EXAMPLES +HASEXAMPLES=1 +override EXAMPLESOURCEFILES:=$(wildcard $(addsuffix .pp,$(TARGET_EXAMPLES)) $(addsuffix .pas,$(TARGET_EXAMPLES))) +override EXAMPLEFILES:=$(addsuffix $(EXEEXT),$(TARGET_EXAMPLES)) +override EXAMPLEOFILES:=$(addsuffix $(OEXT),$(TARGET_EXAMPLES)) $(addprefix $(STATICLIBPREFIX),$(addsuffix $(STATICLIBEXT),$(TARGET_EXAMPLES))) +override CLEANEXEFILES+=$(EXAMPLEFILES) $(EXAMPLEOFILES) +ifeq ($(OS_TARGET),os2) +override CLEANEXEFILES+=$(addsuffix $(AOUTEXT),$(TARGET_EXAMPLES)) +endif +endif +ifdef TARGET_EXAMPLEDIRS +HASEXAMPLES=1 +endif +fpc_examples: all $(EXAMPLEFILES) $(addsuffix _all,$(TARGET_EXAMPLEDIRS)) +.PHONY: fpc_all fpc_smart fpc_debug fpc_release +$(FPCMADE): $(ALLDEPENDENCIES) $(ALLTARGET) + @$(ECHOREDIR) Compiled > $(FPCMADE) +fpc_all: $(FPCMADE) +fpc_smart: + $(MAKE) all LINKSMART=1 CREATESMART=1 +fpc_debug: + $(MAKE) all DEBUG=1 +fpc_release: + $(MAKE) all RELEASE=1 +.SUFFIXES: $(EXEEXT) $(PPUEXT) $(OEXT) .pas .pp .rc .res +%$(PPUEXT): %.pp + $(COMPILER) $< + $(EXECPPAS) +%$(PPUEXT): %.pas + $(COMPILER) $< + $(EXECPPAS) +%$(EXEEXT): %.pp + $(COMPILER) $< + $(EXECPPAS) +%$(EXEEXT): %.pas + $(COMPILER) $< + $(EXECPPAS) +%.res: %.rc + windres -i $< -o $@ +vpath %.pp $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR) +vpath %.pas $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR) +vpath %$(PPUEXT) $(COMPILER_UNITTARGETDIR) +.PHONY: fpc_install fpc_sourceinstall fpc_exampleinstall +ifdef INSTALL_UNITS +override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(INSTALL_UNITS)) +endif +ifdef INSTALL_BUILDUNIT +override INSTALLPPUFILES:=$(filter-out $(INSTALL_BUILDUNIT)$(PPUEXT),$(INSTALLPPUFILES)) +endif +ifdef INSTALLPPUFILES +override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) +override INSTALLPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPUFILES)) +override INSTALLPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPULINKFILES))) +override INSTALL_CREATEPACKAGEFPC=1 +endif +ifdef INSTALLEXEFILES +override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(INSTALLEXEFILES)) +endif +fpc_install: all $(INSTALLTARGET) +ifdef INSTALLEXEFILES + $(MKDIR) $(INSTALL_BINDIR) +ifdef UPXPROG + -$(UPXPROG) $(INSTALLEXEFILES) +endif + $(INSTALLEXE) $(INSTALLEXEFILES) $(INSTALL_BINDIR) +endif +ifdef INSTALL_CREATEPACKAGEFPC +ifdef FPCMAKE +ifdef PACKAGE_VERSION +ifneq ($(wildcard Makefile.fpc),) + $(FPCMAKE) -p -T$(OS_TARGET) Makefile.fpc + $(MKDIR) $(INSTALL_UNITDIR) + $(INSTALL) Package.fpc $(INSTALL_UNITDIR) +endif +endif +endif +endif +ifdef INSTALLPPUFILES + $(MKDIR) $(INSTALL_UNITDIR) + $(INSTALL) $(INSTALLPPUFILES) $(INSTALL_UNITDIR) +ifneq ($(INSTALLPPULINKFILES),) + $(INSTALL) $(INSTALLPPULINKFILES) $(INSTALL_UNITDIR) +endif +ifneq ($(wildcard $(LIB_FULLNAME)),) + $(MKDIR) $(INSTALL_LIBDIR) + $(INSTALL) $(LIB_FULLNAME) $(INSTALL_LIBDIR) +ifdef inUnix + ln -sf $(LIB_FULLNAME) $(INSTALL_LIBDIR)/$(LIB_NAME) +endif +endif +endif +ifdef INSTALL_FILES + $(MKDIR) $(INSTALL_DATADIR) + $(INSTALL) $(INSTALL_FILES) $(INSTALL_DATADIR) +endif +fpc_sourceinstall: distclean + $(MKDIR) $(INSTALL_SOURCEDIR) + $(COPYTREE) $(BASEDIR)/* $(INSTALL_SOURCEDIR) +fpc_exampleinstall: $(addsuffix _distclean,$(TARGET_EXAMPLEDIRS)) +ifdef HASEXAMPLES + $(MKDIR) $(INSTALL_EXAMPLEDIR) +endif +ifdef EXAMPLESOURCEFILES + $(COPY) $(EXAMPLESOURCEFILES) $(INSTALL_EXAMPLEDIR) +endif +ifdef TARGET_EXAMPLEDIRS + $(COPYTREE) $(addsuffix /*,$(TARGET_EXAMPLEDIRS)) $(INSTALL_EXAMPLEDIR) +endif +.PHONY: fpc_clean fpc_cleanall fpc_distclean +ifdef EXEFILES +override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES)) +endif +ifdef CLEAN_UNITS +override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(CLEAN_UNITS)) +endif +ifdef CLEANPPUFILES +override CLEANPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) +override CLEANPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILES)) +override CLEANPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPULINKFILES))) +endif +fpc_clean: $(CLEANTARGET) +ifdef CLEANEXEFILES + -$(DEL) $(CLEANEXEFILES) +endif +ifdef CLEANPPUFILES + -$(DEL) $(CLEANPPUFILES) +endif +ifneq ($(CLEANPPULINKFILES),) + -$(DEL) $(CLEANPPULINKFILES) +endif +ifdef CLEANRSTFILES + -$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES)) +endif +ifdef CLEAN_FILES + -$(DEL) $(CLEAN_FILES) +endif +ifdef LIB_NAME + -$(DEL) $(LIB_NAME) $(LIB_FULLNAME) +endif + -$(DEL) $(FPCMADE) Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE) +fpc_distclean: clean +ifdef COMPILER_UNITTARGETDIR +TARGETDIRCLEAN=fpc_clean +endif +fpc_cleanall: $(CLEANTARGET) $(TARGETDIRCLEAN) +ifdef CLEANEXEFILES + -$(DEL) $(CLEANEXEFILES) +endif + -$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT) + -$(DELTREE) *$(SMARTEXT) + -$(DEL) $(FPCMADE) Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE) +ifdef AOUTEXT + -$(DEL) *$(AOUTEXT) +endif +.PHONY: fpc_baseinfo +override INFORULES+=fpc_baseinfo +fpc_baseinfo: + @$(ECHO) + @$(ECHO) == Package info == + @$(ECHO) Package Name..... $(PACKAGE_NAME) + @$(ECHO) Package Version.. $(PACKAGE_VERSION) + @$(ECHO) + @$(ECHO) == Configuration info == + @$(ECHO) + @$(ECHO) FPC.......... $(FPC) + @$(ECHO) FPC Version.. $(FPC_VERSION) + @$(ECHO) Source CPU... $(CPU_SOURCE) + @$(ECHO) Target CPU... $(CPU_TARGET) + @$(ECHO) Source OS.... $(OS_SOURCE) + @$(ECHO) Target OS.... $(OS_TARGET) + @$(ECHO) Full Source.. $(FULL_SOURCE) + @$(ECHO) Full Target.. $(FULL_TARGET) + @$(ECHO) + @$(ECHO) == Directory info == + @$(ECHO) + @$(ECHO) Required pkgs... $(REQUIRE_PACKAGES) + @$(ECHO) + @$(ECHO) Basedir......... $(BASEDIR) + @$(ECHO) FPCDir.......... $(FPCDIR) + @$(ECHO) CrossBinDir..... $(CROSSBINDIR) + @$(ECHO) UnitsDir........ $(UNITSDIR) + @$(ECHO) PackagesDir..... $(PACKAGESDIR) + @$(ECHO) + @$(ECHO) GCC library..... $(GCCLIBDIR) + @$(ECHO) Other library... $(OTHERLIBDIR) + @$(ECHO) + @$(ECHO) == Tools info == + @$(ECHO) + @$(ECHO) As........ $(AS) + @$(ECHO) Ld........ $(LD) + @$(ECHO) Ar........ $(AR) + @$(ECHO) Rc........ $(RC) + @$(ECHO) + @$(ECHO) Mv........ $(MVPROG) + @$(ECHO) Cp........ $(CPPROG) + @$(ECHO) Rm........ $(RMPROG) + @$(ECHO) GInstall.. $(GINSTALL) + @$(ECHO) Echo...... $(ECHO) + @$(ECHO) Date...... $(DATE) + @$(ECHO) FPCMake... $(FPCMAKE) + @$(ECHO) PPUMove... $(PPUMOVE) + @$(ECHO) Upx....... $(UPXPROG) + @$(ECHO) Zip....... $(ZIPPROG) + @$(ECHO) + @$(ECHO) == Object info == + @$(ECHO) + @$(ECHO) Target Loaders........ $(TARGET_LOADERS) + @$(ECHO) Target Units.......... $(TARGET_UNITS) + @$(ECHO) Target Implicit Units. $(TARGET_IMPLICITUNITS) + @$(ECHO) Target Programs....... $(TARGET_PROGRAMS) + @$(ECHO) Target Dirs........... $(TARGET_DIRS) + @$(ECHO) Target Examples....... $(TARGET_EXAMPLES) + @$(ECHO) Target ExampleDirs.... $(TARGET_EXAMPLEDIRS) + @$(ECHO) + @$(ECHO) Clean Units......... $(CLEAN_UNITS) + @$(ECHO) Clean Files......... $(CLEAN_FILES) + @$(ECHO) + @$(ECHO) Install Units....... $(INSTALL_UNITS) + @$(ECHO) Install Files....... $(INSTALL_FILES) + @$(ECHO) + @$(ECHO) == Install info == + @$(ECHO) + @$(ECHO) DateStr.............. $(DATESTR) + @$(ECHO) ZipPrefix............ $(ZIPPREFIX) + @$(ECHO) ZipSuffix............ $(ZIPSUFFIX) + @$(ECHO) Install FPC Package.. $(INSTALL_FPCPACKAGE) + @$(ECHO) + @$(ECHO) Install base dir..... $(INSTALL_BASEDIR) + @$(ECHO) Install binary dir... $(INSTALL_BINDIR) + @$(ECHO) Install library dir.. $(INSTALL_LIBDIR) + @$(ECHO) Install units dir.... $(INSTALL_UNITDIR) + @$(ECHO) Install source dir... $(INSTALL_SOURCEDIR) + @$(ECHO) Install doc dir...... $(INSTALL_DOCDIR) + @$(ECHO) Install example dir.. $(INSTALL_EXAMPLEDIR) + @$(ECHO) Install data dir..... $(INSTALL_DATADIR) + @$(ECHO) + @$(ECHO) Dist destination dir. $(DIST_DESTDIR) + @$(ECHO) Dist zip name........ $(DIST_ZIPNAME) + @$(ECHO) +.PHONY: fpc_info +fpc_info: $(INFORULES) +.PHONY: fpc_makefile fpc_makefiles fpc_makefile_sub1 fpc_makefile_sub2 \ + fpc_makefile_dirs +fpc_makefile: + $(FPCMAKE) -w -T$(OS_TARGET) Makefile.fpc +fpc_makefile_sub1: +ifdef TARGET_DIRS + $(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_DIRS)) +endif +ifdef TARGET_EXAMPLEDIRS + $(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_EXAMPLEDIRS)) +endif +fpc_makefile_sub2: $(addsuffix _makefile_dirs,$(TARGET_DIRS) $(TARGET_EXAMPLEDIRS)) +fpc_makefile_dirs: fpc_makefile_sub1 fpc_makefile_sub2 +fpc_makefiles: fpc_makefile fpc_makefile_dirs +all: fpc_all +debug: fpc_debug +smart: fpc_smart +release: fpc_release +examples: fpc_examples +shared: +install: fpc_install +sourceinstall: fpc_sourceinstall +exampleinstall: fpc_exampleinstall +distinstall: +zipinstall: +zipsourceinstall: +zipexampleinstall: +zipdistinstall: +clean: fpc_clean +distclean: fpc_distclean +cleanall: fpc_cleanall +info: fpc_info +makefiles: fpc_makefiles +.PHONY: all debug smart release examples shared install sourceinstall exampleinstall distinstall zipinstall zipsourceinstall zipexampleinstall zipdistinstall clean distclean cleanall info makefiles +ifneq ($(wildcard fpcmake.loc),) +include fpcmake.loc +endif diff --git a/fcl/db/odbc/Makefile.fpc b/fcl/db/odbc/Makefile.fpc new file mode 100644 index 0000000000..c970cceeae --- /dev/null +++ b/fcl/db/odbc/Makefile.fpc @@ -0,0 +1,28 @@ +# +# Makefile.fpc for fpODBC db units +# + +[package] +main=fcl + +[target] +units=fpodbc +examples=testbcon testcon testdrcon testenv testfl testpa testpk\ + testpr testsql testst testtl + + +[clean] +units= + +[require] +packages=odbc + +[compiler] +options=-S2 +targetdir=../../$(OS_TARGET) + +[install] +fpcpackage=y + +[default] +fpcdir=../../.. diff --git a/fcl/db/odbc/README b/fcl/db/odbc/README new file mode 100644 index 0000000000..9a1afca624 --- /dev/null +++ b/fcl/db/odbc/README @@ -0,0 +1,181 @@ +fpODBC - a OOP wrapper around the ODBC driver. + +This is a simple OOP wrapper around teh ODBC data calls. + +There are basically 3 classes: + +TODBCEnvironment +---------------- + A global object the contains the connection to the ODBC driver. Each + connection should have an environment assigned to it. If not, a + default environment will be used. + + It has the following methods: + + Function GetDriverNames(List : Tstrings) : Integer; + Fills list with the available drivers. Returns the number of + drivers. + + Function GetDataSourceNames(List : Tstrings; Types : TDSNTypes;Descriptions : Boolean) : Integer; + Fills list with the available datasources. + Types is one of + dtUser : Return only user DSNs + dtSystem : Return system DSNs + dtBoth : Return both + The function returns the number of returned drivers. + + function GetDriverOptions(Driver: String; Options: TStrings): Integer; + Returns a list of options for the driver. + +TODBCConnection + + Represents a connection to a ODBC datasource. + The connection is established according to the following rules: + - If OnBrowseConnection is assigned, SQLBrowseConnect is used. At + each browse step, the handler is called with the in and out + parameter lists filled. + TConnectionBrowseEvent = Procedure (Sender : TObject;InParams,OutParams : Tstrings) of Object; + + This is as yet untested, since I have no driver which supports it. + + - If the DSN property is assigned, this is used. Password and Username are also used. + + - If The drivername is assigned, that is used, together with the + DriverParams. This should be a list name=value pairs which will be + passed to the driver. + + - If none of the above conditions is fullfilled, an error is raised. + + - To connect, set the Active property to 'True' or call connect. + + - To Disconnect, set the active property to false or call disconnect + + The following methods exist: + + Procedure Connect; + Connects to the DSN/Driver + + Procedure Disconnect; + Disconnects from the DSN/Driver + + Procedure GetTableNames(S : TStrings; SystemTables : Boolean); + + returns a list of tables. If systemtables is true, then system + table names are also returned. + + Procedure GetFieldNames(TableName : String; S : TStrings); + returns a list of fieldnames for table 'tablename' + Procedure GetPrimaryKeyFields(TableName : String; S : TStrings); + returns a list of primary key fieldnames for table 'tablename' + procedure GetProcedureNames(S : TStrings); + returns a list of stored procedure names + procedure GetProcedureParams(ProcName : String;ParamTypes : TODBCParamTypes; S : TStrings); + returns a list of parameters for the stored procedure. ParamTypes is a set of + ptUnknown,ptInput,ptInputOutput,ptResult,ptOutput,ptRetVal + + +TODBCStatement / TODBCSQLStatement. + + TODBCStatement is an abstract class which encapsulates an ODBC Statement + handle. TODBCSQLStatement accepts an SQL Query which it can execute. + + TODBCStatement has the following methods: + + Procedure BindFields(RestrictList : TStrings);virtual; + Binds fields. If restrictlist is assigned, then only fields whose + name appears in the list are bound. + Procedure ClearFields;virtual; + clears the field definitions. + Function Fetch : Boolean; + fetches the next row. Is false if there was no more data. + Property Connection : TODBCConnection Read FConnection Write SetConnection; + The connection object to use. + Property BOF : Boolean read FBOF; + True if at beginning of data + Property EOF : Boolean read FEOF; + True if at end of data + Property Fields : TODBCFieldList Read FFields; + Collection of fields in result set (if any) + + TODBCSQLStatement has the following extra methods/properties: + + procedure Prepare; + prepares the query. After this, Bindfields may be called. + procedure Unprepare; + unprepares the query. After this, Bindfields nor execute may be called. + procedure ExecSQL; + executes the SQL query. If it was not prepared it is executed + directly. + Procedure Open; + prepares the query, binds all fields, allocates buffers and + fetches the first row of the result set. + Procedure Close; + Undoes the 'Open' + procedure GetFieldList(List: TStrings); + Retsurns a list of field names in the result set. Can only be + called after Prepare/Open and before close. + Property Active : Boolean Read GetActive Write SetActive; + Setting Active to true is the same as calling open. + Setting it to false is the same as calling close. + Property SQL : TStrings + The SQL statement to be executed. + + + A query result is returned in a collection of TODBCField objects: + +TODBCField : + Property Position : SQLSmallint Read FPosition; + (position in the query) + Property Name : String read FName; + (name of the field) + Property DataType : SQLSmallInt read FDatatype; + (original SQL data type) + Property Size : SQLUinteger read FSize; + (Original SQL data size) + property DecimalDigits : SQLSmallInt read FDecimalDigits; + (Original SQL digits after decimal point) + Property Nullable : Boolean Read FNullable; + (Field is nullable ?) + Property Data : Pchar Read GetData; + (pointer to raw data) + Property BufType : SQLSmallInt Read FBufType; + (SQL type of the allocated data buffer) + Property BufSize : SQLInteger Read FBufSize; + (Allocated size of the buffer) + Property IsNull : Boolean Read GetIsNull; + (Was the returned field value null ?) + + Property AsString : String Read GetAsString; + Field value as string. + Property AsInteger : Integer Read GetAsInteger; + Field value as integer. + Property AsBoolean : Boolean Read GetAsBoolean; + Field value as boolean. + Property AsDouble : Double Read GetAsDouble; + Field value as DOUBLE + Property AsDateTime : TDateTime Read GetAsDateTime; + Field value as TDateTime + + The latter properties do some basic conversion i.e. + if the result is an integer, the AsString will return + the integer value converted to a string. + + Blob is not yet supported, but should be soon. + +List of examples: + +Program test functionality +------- ----------------- + +testbcon.pp tests browseconnect. +testcon.pp tests DSN connect. +testdrcon.pp tests driverconnect. +testenv.pp test ennvironment functions. +testfl.pp test fieldlist. +testodbc.pp test raw odbc. +testpa.pp test procedure arguments. +testpk.pp test primary key lists. +testpr.pp test procedure list. +testsql.pp test execution of SQL and retrieval of results. +testst.pp test preparing of a statement. +testtl.pp test table list. diff --git a/fcl/db/odbc/fpodbc.pp b/fcl/db/odbc/fpodbc.pp new file mode 100644 index 0000000000..a00b741d1b --- /dev/null +++ b/fcl/db/odbc/fpodbc.pp @@ -0,0 +1,1465 @@ +unit fpodbc; + +{$mode objfpc} +{$h+} + +interface + +uses odbcsql,SysUtils,Classes; + +Type + TDSNTypes = (dtUser,dtSystem,dtBoth); + TODBCParamType = (ptUnknown,ptInput,ptInputOutput,ptResult,ptOutput,ptRetVal); + TODBCParamTypes = Set of TODBCParamType; + + TODBCObject = Class(TComponent) + Private + FHandle : SQLHandle; + FHandleType : SQLSmallint; + Function GetHandle : SQLHandle; + function GetHandleAllocated: Boolean; + function GetExtendedErrorInfo: String; + Protected + Function CreateHandle : SQLHandle; Virtual; + Function ParentHandle : SQLHandle; Virtual; + Procedure FreeHandle; + Function CheckODBC(Res : Integer;Msg : String) : Integer; + Public + Destructor Destroy; override; + Property Handle : SQLHandle Read GetHandle; + Property HandleAllocated : Boolean Read GetHandleAllocated; + end; + + TODBCEnvironment = Class(TODBCObject) + Private + FODBCBehaviour : Integer; + procedure SetODBCbehaviour(const Value: Integer); + function GetNullTerminate: Boolean; + procedure SetNullTerminate(const Value: Boolean); + protected + function CreateHandle: SQLHandle; override; + Procedure SetIntAttribute(Const Attr,Value : Integer); + Procedure SetStringAttribute(Const Attr: Integer; Value : String); + Function GetIntAttribute(Const Attr : Integer) : Integer; + Function GetStringAttribute(Const Attr : Integer) : String; + Public + Constructor Create(Aowner : TComponent);override; + Function GetDriverNames(List : Tstrings) : Integer; + Function GetDataSourceNames(List : Tstrings; Types : TDSNTypes;Descriptions : Boolean) : Integer; + function GetDriverOptions(Driver: String; Options: TStrings): Integer; + Property ODBCBehaviour : Integer Read FODBCBehaviour Write SetODBCbehaviour; + Property NullTerminateStrings : Boolean Read GetNullTerminate Write SetNullTerminate; + end; + + TConnectionBrowseEvent = Procedure (Sender : TObject;InParams,OutParams : Tstrings) of Object; + + TODBCConnection = Class(TODBCObject) + Private + FActive : Boolean; + FDriverParams : TStrings; + FDSN, + FDriverName, + FUserName, + FPassword : String; + FEnvironMent : TODBCEnvironment; + FOnBrowseConnection : TConnectionBrowseEvent; + FWindowHandle : integer; + FDriverCOmpletion: SQLUSmallInt; + function GetDriverName: String; + function GetDriverParams: TStrings; + procedure SetActive(const Value: Boolean); + procedure SetDriverName(const Value: String); + procedure SetDriverParams(const Value: TStrings); + procedure SetDSN(const Value: String); + function GetEnvironment: TODBCEnvironMent; + procedure SetEnvironment(const Value: TODBCEnvironMent); + Protected + procedure ConnectToDriver; + procedure ConnectToDSN; + Procedure ConnectBrowsing; + Function ParentHandle : SQLHandle; override; + Procedure CheckActive; + Procedure CheckInActive; + Public + Constructor Create(Aowner : TComponent);override; + Destructor Destroy; override; + Procedure Connect; + Procedure Disconnect; + Procedure GetTableNames(S : TStrings; SystemTables : Boolean); + Procedure GetFieldNames(TableName : String; S : TStrings); + Procedure GetPrimaryKeyFields(TableName : String; S : TStrings); + procedure GetProcedureNames(S : TStrings); + procedure GetProcedureParams(ProcName : String;ParamTypes : TODBCParamTypes; S : TStrings); + Property DSN : String Read FDSN Write SetDSN; + Property DriverName : String Read GetDriverName Write SetDriverName; + Property DriverCompletion : SQLUSmallInt Read FDriverCOmpletion Write FDriverCompletion; + Property DriverParams : TStrings Read GetDriverParams Write SetDriverParams; + Property Active : Boolean Read FActive Write SetActive; + Property Environment : TODBCEnvironMent Read GetEnvironment Write SetEnvironment; + Property UserName : String Read FUserName Write FUserName; + Property Password : string Read FPassword Write FPassword; + Property OnBrowseConnection : TConnectionBrowseEvent Read FonBrowseConnection Write FOnBrowseConnection; + Property WindowHandle : integer Read FWindowHandle Write FWindowHandle; + end; + + TODBCStatement = Class; + + TODBCFieldList = Class(TCollection) + Private + FStatement : TODBCStatement; + Public + Constructor Create(Statement : TODBCStatement); + end; + + { + TODBCStatement allocates 1 big data buffer. For each bound field + two things are allocated in the buffer: + - Size of fetched data as filled in by fetch. + - data. (may be zero for blobs etc) + The FBuffOffset contains the offset in the buffer of the size field. + Data immediatly follows the size. + } + + TODBCField = Class(TCollectionItem) + Private + FDecimalDigits, + FPosition : SQLSmallInt; + FName : String; + FSize : SQLUInteger; // Declared size, as returned by DescribeCol + FNullable : Boolean; + FDataType : SQLSmallInt; // Declared type, as returned by DescribeCol + FBuffOffSet : SQLInteger; // Offset in data buffer. + FBuffer : Pointer; // Pointer to data. + FBufSize : SQLInteger; // Allocated buffer size. + FBufType : SQLSmallInt; // Allocated buffer type + function GetAsString: String; + function GetData : PChar; + Function GetIsNull : Boolean; + Function GetAsInteger : Integer; + Function GetAsBoolean : Boolean; + Function GetAsDouble : Double; + Function GetAsDateTime : TDateTime; + Public + Property Position : SQLSmallint Read FPosition; + Property Name : String read FName; + Property DataType : SQLSmallInt read FDatatype; + Property Size : SQLUinteger read FSize; + property DecimalDigits : SQLSmallInt read FDecimalDigits; + Property Nullable : Boolean Read FNullable; + Property Data : Pchar Read GetData; + Property BufType : SQLSmallInt Read FBufType; + Property BufSize : SQLInteger Read FBufSize; + Property IsNull : Boolean Read GetIsNull; + Property AsString : String Read GetAsString; + Property AsInteger : Integer Read GetAsInteger; + Property AsBoolean : Boolean Read GetAsBoolean; + Property AsDouble : Double Read GetAsDouble; + Property AsDateTime : TDateTime Read GetAsDateTime; + end; + + TODBCStatement = Class(TODBCObject) + Private + FBOF,FEOF : Boolean; + FConnection: TODBCConnection; + FFields : TODBCFieldList; + FBuffer : Pointer; + Protected + Function ParentHandle : SQLHandle; override; + procedure SetConnection(const Value: TODBCConnection); + procedure AllocBuffers; + Public + Constructor Create(Aowner : TComponent);override; + Destructor Destroy; override; + Procedure BindFields(RestrictList : TStrings);virtual; + Procedure ClearFields;virtual; + Function Fetch : Boolean; + Property Connection : TODBCConnection Read FConnection Write SetConnection; + Property BOF : Boolean read FBOF; + Property EOF : Boolean read FEOF; + Property Fields : TODBCFieldList Read FFields; + end; + + TODBCTableList = Class(TODBCStatement) + Public + Procedure GetTableNames(S : TStrings; SystemTables : Boolean); + end; + + TODBCFieldNamesList = Class(TODBCStatement) + Public + Procedure GetFieldNames(TableName : String;S : TStrings); + end; + + TODBCPrimaryKeyFieldsList = Class(TODBCStatement) + Public + Procedure GetPrimaryKeyFields(TableName : String;S : TStrings); + end; + + TODBCProcedureList = Class(TODBCStatement) + Public + Procedure GetProcedureList(S : TStrings); + end; + + TODBCProcedureParams = Class(TODBCStatement) + Procedure GetProcedureParams(ProcName: String; ParamTypes: TODBCParamTypes; S: TStrings); + end; + + TStatementState = (ssInactive,ssPrepared,ssBound,ssOpen); + + TODBCSQLStatement = Class(TODBCStatement) + Private + FSQL : TStrings; + FState : TStatementState; + function GetActive: Boolean; + procedure SetActive(const Value: Boolean); + Protected + procedure FreeStatement(Option: SQLUSMALLINT); + procedure ExecuteDirect; + procedure ExecutePrepared; + Procedure SetSQL(const Value: TStrings); + Public + Constructor Create(Aowner : TComponent);override; + Destructor Destroy; override; + procedure Prepare; + procedure Unprepare; + Procedure BindFields(RestrictList : TStrings);override; + procedure ExecSQL; + Procedure Open; + Procedure Close; + procedure GetFieldList(List: TStrings); + Property Active : Boolean Read GetActive Write SetActive; + Property SQL : TStrings Read FSQL Write SetSQL; + end; + + EODBCError = Class(Exception); + +Const + ODBCParamTypeNames : Array [TODBCParamType] of string + = ('Unknown','Input','Input/Output','Result','Output','RetVal'); + +Function DefaultEnvironment : TODBCEnvironment; + +implementation + +{ TODBCObject } + +resourcestring + SErrUnexpected = 'Unexpected ODBC error:'; + SErrEnvironmentHandle = 'Cannot allocate environment handle:'; + SErrInvalidBehaviour = 'Invalid value for ODBC behaviour: %d'; + SErrNotConnected = 'Operation invalid when not connected.'; + SErrConnected = 'Operation invalid when connected.'; + SNeedDSNOrDriver = 'Cannot connect with empty DSN and driver names.'; + SErrGettingDataSources = 'Error getting datasources:'; + SErrGettingDriverNames = 'Error getting driver names:'; + SErrGettingDriverOptions = 'Error getting driver options:'; + SErrSettingEnvAttribute = 'Error setting environment attribute:'; + SErrGettingEnvAttribute = 'Error Getting environment attribute:'; + SErrBrowseConnecting = 'Error connecting to datasource via browse:'; + SErrDSNConnect = 'Error connecting to DSN:'; + SErrDriverConnect = 'Error connecting to driver:'; + SErrDisconnecting = 'Error disconnecting:'; + SErrNoConnectionForStatement = 'Missing connection for statement.'; + SErrNoSQLStatement = 'Missing SQL statement.'; + SErrPreparing = 'Error preparing statement:'; + SErrGettingTableNames = 'Error getting table names:'; + SErrFetchingData = 'Error fetching data:'; + SErrFieldNames = 'Error getting field names:'; + SErrPrimaryKeys = 'Error getting primary key names:'; + SErrProcedureNames = 'Error getting procedure names:'; + SErrExecuting = 'Error while executing statement:'; + SErrExecutingPrepared = 'Error while executing prepared statement:'; + SErrNotPrepared = 'Statement is not prepared'; + SErrNotInactive = 'Statement is already prepared or executed.'; + SErrStatementActive = 'A statement is still active'; + SErrColumnCount = 'Error retrieving cilumn count:'; + SErrColDescription = 'Error retrieving column description'; + SErrInvalidConversion = 'invalid type conversion'; + SErrBindCol = 'Error binding column'; +Const + ODBCSuccess = [SQL_SUCCESS,SQL_SUCCESS_WITH_INFO]; + +Procedure ODBCError (Msg : String); + +begin + Raise EODBCError.Create(Msg); +end; + +Procedure ODBCErrorFmt (Fmt : String;Args : Array of const); + +begin + Raise EODBCError.CreateFmt(Fmt,Args); +end; + +Function CheckODBC(Res : Integer;Msg : String) : Integer; + +begin + Result:=Res; + if not Res in [SQL_SUCCESS,SQL_SUCCESS_WITH_INFO] then + begin + If MSG='' then + MSG:=SErrUnexpected; + ODBCErrorFmt(msg,[res]); + end; +end; + +function TODBCObject.CheckODBC(Res: Integer; Msg: String): Integer; + +Var S : String; + +begin + Result:=Res; + if not Res in [SQL_SUCCESS,SQL_SUCCESS_WITH_INFO] then + begin + If MSG='' then + MSG:=SErrUnexpected; + S:=GetExtendedErrorInfo; + If S<>'' then + Msg:=Msg+LineEnding+S; + ODBCError(msg); + end; +end; + +function TODBCObject.GetExtendedErrorInfo : String; + +Var + Res : SQLreturn; + I,MsgLen : SQLSmallInt; + SQLState : Array[0..6] of Char; + NativeError : SQLInteger; + MSg : Array[0..SQL_MAX_MESSAGE_LENGTH] of Char; + SState,SMsg : String; + +begin + I:=0; + Result:=''; + Repeat + Inc(i); + Res:=SQLGetDiagRec(FhandleType, FHandle, i, SqlState, NativeError, + Msg, sizeof(Msg), MsgLen); + If Res<>SQL_NO_DATA then + begin + SState:=SQLState; + SMsg:=Msg; + If Length(Result)>0 then + Result:=Result+LineEnding; + Result:=Result+Format('[%s] : %s (%d)',[SState,SMsg,NativeError]); + end; + Until (Res=SQL_NO_DATA); +end; + + + + +function TODBCObject.CreateHandle: SQLHandle; +begin +{$ifdef debug} + Writeln(Classname,': Creating handle of type ',FHAndleType,' and parent ',ParentHandle); +{$endif} + CheckODBC(SQLAllocHandle(FHandleType,ParentHandle,FHandle),SErrEnvironmentHandle); + Result:=FHandle; +end; + + +destructor TODBCObject.Destroy; +begin + If FHandle<>0 then + FreeHandle; + inherited; +end; + +procedure TODBCObject.FreeHandle; +begin + If FHandle<>0 then + begin + SQLFreeHandle(FHandleType,FHandle); + FHandle:=0; + end; +end; + +function TODBCObject.GetHandle: SQLHandle; +begin + If FHandle=0 then + CreateHandle; + Result:=FHandle; +end; + +function TODBCObject.GetHandleAllocated: Boolean; +begin + Result:=(FHandle<>0) +end; + +function TODBCObject.ParentHandle: SQLHandle; +begin + Result:=SQL_NULL_HANDLE; +end; + +{ TODBCEnvironment } + +constructor TODBCEnvironment.Create(Aowner: TComponent); +begin + FHandleType:=SQL_HANDLE_ENV; + inherited; +end; + +function TODBCEnvironment.CreateHandle: SQLHandle; +begin + Result:=Inherited CreateHandle; + ODBCbehaviour:=SQL_OV_ODBC3; +end; + +function TODBCEnvironment.GetDataSourceNames(List: Tstrings; + Types: TDSNTypes;Descriptions : Boolean): Integer; + +var + DSNName, + DSNDesc: array[0..SQL_MAX_OPTION_STRING_LENGTH] of Char; + lenn,lend : SQLSmallInt; + Dir : SQLSmallInt; + Sn,SD : String; + +begin + Case Types of + dtSystem : Dir:=SQL_FETCH_FIRST_SYSTEM; + dtUser : Dir:=SQL_FETCH_FIRST_USER; + dtBoth : Dir:=SQL_FETCH_FIRST; + end; + List.Clear; + CheckODBC(SQLDatasources(Handle, Dir, + DSNName,SQL_MAX_OPTION_STRING_LENGTH, @lenn, + DSNDesc,SQL_MAX_OPTION_STRING_LENGTH, @lend),SErrGettingDataSources); + Repeat + If Not Descriptions then + List.Add(DSNName) + else + begin + SN:=DSNName; + SD:=DSNDesc; + List.Add(SN+'='+SD); + end; + Until Not (SQLDataSources(Handle, SQL_FETCH_NEXT, + DSNName, SQL_MAX_OPTION_STRING_LENGTH, @lenn, + DSNDesc,SQL_MAX_OPTION_STRING_LENGTH, @lend) in ODBCSuccess); + Result:=List.Count; +end; + +function TODBCEnvironment.GetDriverNames(List : Tstrings): Integer; + +Var + DriverName: array[0..SQL_MAX_OPTION_STRING_LENGTH] of Char; + len : SQLSmallInt; + +begin + List.Clear; + CheckODBC(SQLDrivers(Handle, SQL_FETCH_FIRST, DriverName, + SQL_MAX_OPTION_STRING_LENGTH, @len, Nil,0,Nil),SErrGettingDriverNames); + Repeat + List.Add(DriverName); + Until Not (SQLDrivers(Handle, SQL_FETCH_NEXT, DriverName, + SQL_MAX_OPTION_STRING_LENGTH, @len, Nil,0,Nil) in ODBCSuccess); + Result:=List.Count; +end; + +function TODBCEnvironment.GetDriverOptions(Driver : String;Options: Tstrings): Integer; + +Var + DriverName, + DriverOptions: array[0..SQL_MAX_OPTION_STRING_LENGTH] of Char; + lenn,leno : SQLSmallInt; + Found : Boolean; + P : PChar; + S : string; + +begin + CheckODBC(SQLDrivers(Handle, SQL_FETCH_FIRST, DriverName, + SQL_MAX_OPTION_STRING_LENGTH, @lenn, DriverOptions, + SQL_MAX_OPTION_STRING_LENGTH,@Leno),SErrGettingDriverOptions); + Result:=0; + Options.Clear; + Repeat + Found:=CompareText(Driver,DriverName)=0; + If Found then + begin + P:=@DriverOptions[0]; + While P[0]<>#0 do + begin + S:=StrPas(P); + options.Add(S); + Inc(P,Length(S)+1); + end; + end; + Until Not (SQLDrivers(Handle, SQL_FETCH_NEXT, DriverName, + SQL_MAX_OPTION_STRING_LENGTH, @lenn, DriverOptions, + SQL_MAX_OPTION_STRING_LENGTH,@Leno) in ODBCSuccess) or Found; + Result:=Options.Count; +end; + +function TODBCEnvironment.GetIntAttribute(const Attr: Integer): Integer; +begin + CheckODBC(SQLSetEnvAttr(Handle,Attr,SQLPointer(@result),0),SErrSettingEnvAttribute); +end; + +function TODBCEnvironment.GetNullTerminate: Boolean; +begin + Result:=(GetIntAttribute(SQL_ATTR_OUTPUT_NTS)=SQL_TRUE); +end; + +function TODBCEnvironment.GetStringAttribute(const Attr: Integer): String; + +Var + OldLen,Len: Integer; + +begin + OldLen:=0; + Repeat + Inc(OldLen,255); + SetLength(Result,OldLen); + CheckODBC(SQLGetEnvAttr(Handle,Attr,SQLPointer(@result),OldLen,@Len),SErrGettingEnvAttribute); + until (Len<=OldLen); + SetLength(Result,Len); +end; + +procedure TODBCEnvironment.SetIntAttribute(const Attr, Value: Integer); +begin + CheckODBC(SQLSetEnvAttr(Handle,Attr,SQLPointer(Value),0),SErrSettingEnvAttribute); +end; + +procedure TODBCEnvironment.SetNullTerminate(const Value: Boolean); +begin + If Value then + SetIntAttribute(SQL_ATTR_OUTPUT_NTS,SQL_TRUE) + else + SetIntAttribute(SQL_ATTR_OUTPUT_NTS,SQL_FALSE); +end; + +procedure TODBCEnvironment.SetODBCbehaviour(const Value: Integer); +begin + If (Value<>FODBCBehaviour) then + begin + If Not (Value in [SQL_OV_ODBC3,SQL_OV_ODBC2]) Then + ODBCErrorFmt(SErrInvalidBehaviour,[Value]); + SetIntAttribute(SQL_ATTR_ODBC_VERSION,Value); + FODBCBehaviour := Value; + end; +end; + +procedure TODBCEnvironment.SetStringAttribute(const Attr: Integer; + Value: String); +begin + CheckODBC(SQLSetEnvAttr(Handle,Attr,SQLPointer(Value),Length(Value)),SErrSettingEnvAttribute); +end; + +{ TODBCConnection } + +procedure TODBCConnection.CheckActive; +begin + If Not FActive then + ODBCError(SErrNotConnected); +end; + +procedure TODBCConnection.CheckInActive; +begin + If FActive then + ODBCError(SErrConnected); +end; + +procedure TODBCConnection.Connect; +begin + If Not FActive then + begin + If Assigned (FonBrowseConnection) then + ConnectBrowsing + else If (FDSN<>'') then + ConnectToDSN + else if FDriverName<>'' then + ConnectToDriver + else + ODBCError(SNeedDSNOrDriver); + FActive:=True; + end; +end; + +Function ListToBuf(List : Tstrings; Buf : PChar; Sep : Char; MaxLen : Integer) : Boolean; + +Var + P : PChar; + S : String; + I,Len : Integer; + +begin + P:=Buf; + I:=0; + Result:=True; + While Result and (I#0) or (totlen#0 then + Inc(P,1); + inc(Totlen,Len+1); + end; + Result:=List.Count; +end; + + +Procedure TODBCConnection.ConnectBrowsing; + +Var + Inlist,OutList : TStringList; + InStr, + OutStr: Array[0..SQL_MAX_OPTION_STRING_LENGTH] of Char; + i,Res : Integer; + olen : SQLSmallint; + +begin + InList:=TStringList.Create; + OutList:=TstringList.Create; + try + If FDSN<>'' then + InList.Add('DSN='+FDSN) + else If FDriverName<>'' then + begin + Inlist.Add('DRIVER='+FDriverName); + For I:=0 to DriverParams.Count-1 do + Inlist.Add(DriverParams[i]); + end; + Repeat + ListToBuf(Inlist,Instr,';',SQL_MAX_OPTION_STRING_LENGTH); + Res:=SQLBrowseConnect(Handle,Instr,SQL_NTS,Outstr,SQL_MAX_OPTION_STRING_LENGTH,Olen); + If RES=SQL_NEED_DATA then + begin + OutList.Clear; + BufToList(OutStr,Olen,OutList,';'); + FOnBrowseConnection(Self,InList,OutList); + end + Until (Res<>SQL_NEED_DATA); + CheckODBC(Res,SErrBrowseConnecting); + Finally + Outlist.free; + InList.Free; + end; +end; + +Procedure TODBCConnection.ConnectToDSN; +begin + CheckODBC(SQLConnect(Handle,PSQLChar(FDSN),SQL_NTS, + PSQLChar(FUserName),SQL_NTS, + PSQLChar(FPassword),SQL_NTS),SErrDSNConnect); +end; + + +Procedure TODBCConnection.ConnectToDriver; + +Var + Instr, + OutStr : Array[0..SQL_MAX_OPTION_STRING_LENGTH] of Char; + OLen : SQLSmallint; + InList : TStringList; + +begin + InList:=TStringList.Create; + Try + Inlist.Assign(DriverParams); + Inlist.Insert(0,'DRIVER={'+DRIVERNAME+'}'); + ListToBuf(Inlist,InStr,';',SQL_MAX_OPTION_STRING_LENGTH); + Finally + Inlist.Free; + end; + CheckODBC(SQLDriverConnect(Handle,FWindowHandle, + Instr,SQL_NTS, + OutStr,SQL_MAX_OPTION_STRING_LENGTH, + Olen,FDriverCompletion),SErrDriverConnect); +end; + +constructor TODBCConnection.Create(Aowner: TComponent); +begin + inherited; + FHandleType:=SQL_HANDLE_DBC; + FDriverParams:=TStringList.Create; + FDriverCompletion:=SQL_DRIVER_NOPROMPT; +end; + +destructor TODBCConnection.Destroy; +begin + Disconnect; + inherited; +end; + +procedure TODBCConnection.Disconnect; +begin + If FActive then + begin + CheckODBC(SQLDisconnect(Handle),SErrDisconnecting); + Factive:=False; + end; +end; + +function TODBCConnection.GetDriverName: String; +begin + Result:=FDriverName; +end; + +function TODBCConnection.GetDriverParams: TStrings; +begin + Result:=FDriverParams; +end; + +function TODBCConnection.GetEnvironment: TODBCEnvironMent; +begin + If FEnvironment=Nil then + result:=DefaultEnvironment + else + Result:=FEnvironment; +end; + +procedure TODBCConnection.SetActive(const Value: Boolean); +begin + If Value then + Connect + else + Disconnect; +end; + +procedure TODBCConnection.SetDriverName(const Value: String); +begin + CheckInactive; + FDSN:=''; + If CompareText(FDriverName,Value)<>0 then + begin + FDriverName:=Value; + FDriverParams.Clear; + end; +end; + +procedure TODBCConnection.SetDriverParams(const Value: TStrings); +begin + CheckInactive; + FDriverParams.Assign(Value); +end; + +procedure TODBCConnection.SetDSN(const Value: String); +begin + CheckInactive; + FDSN := Value; +end; + +procedure TODBCConnection.SetEnvironment(const Value: TODBCEnvironMent); +begin + CheckInactive; + If (Value<>Environment) then // !! may be defaultenvironment... + begin + If HandleAllocated then + FreeHandle; + FEnvironment:=Value + end; +end; + + +function TODBCConnection.ParentHandle: SQLHandle; +begin + Result:=Environment.Handle +end; + +Const + DefEnv : Pointer = Nil; + +Function DefaultEnvironment : TODBCEnvironment; + +begin + If DefEnv=Nil then + DefEnv:=TODBCEnvironment.Create(Nil); + Result:=TODBCEnvironment(DefEnv); +end; + +procedure TODBCConnection.GetTableNames(S: TStrings; + SystemTables: Boolean); +begin + With TODBCTableList.Create(Self) do + try + GetTableNames(S,SystemTables); + finally + Free; + end; +end; + +procedure TODBCConnection.GetFieldNames(TableName: String; S: TStrings); +begin + With TODBCFieldNamesList.Create(Self) do + try + GetFieldNames(TableName,S); + finally + Free; + end; +end; + +procedure TODBCConnection.GetPrimaryKeyFields(TableName: String; + S: TStrings); +begin + With TODBCPrimaryKeyFieldsList.Create(Self) do + try + GetPrimaryKeyFields(TableName,S); + finally + Free; + end; +end; + +procedure TODBCConnection.GetProcedureNames(S: TStrings); +begin + With TODBCProcedureList.Create(Self) do + try + GetProcedureList(S); + Finally + Free; + end; +end; + +procedure TODBCConnection.GetProcedureParams(ProcName: String; + ParamTypes: TODBCParamTypes; S: TStrings); +begin + With TODBCProcedureParams.Create(Self) do + Try + GetProcedureParams(ProcName,Paramtypes,S); + finally + Free; + end; +end; + +{ TODBCStatement } + +Type + TODBCFieldBufRec = Record + T{ype} : SQlSmallint; + B{ufsize} : SQLInteger; + {Buftyp}e : SQLSmallint; + end; + +Const + BufDescrCount = 26; + BufDescr : Array[1..BufDescrCount] of TODBCFieldBufRec = + { Type Bufsize Buftype } + ( + (T:SQL_CHAR ;b:-1 ;e: SQL_CHAR), + (T:SQL_NUMERIC ;b:sizeof(SQLDouble) ;e: SQL_DOUBLE), + (T:SQL_DECIMAL ;b:sizeof(SQLDouble) ;e: SQL_DOUBLE), + (T:SQL_INTEGER ;b:sizeof(SQLInteger) ;e: SQL_INTEGER), + (T:SQL_SMALLINT ;b:sizeof(SQLSmallInt) ;e: SQL_SMALLINT), + (T:SQL_FLOAT ;b:sizeof(SQLDOUBLE) ;e: SQL_DOUBLE), + (T:SQL_REAL ;b:sizeof(SQLDOUBLE) ;e: SQL_DOUBLE), + (T:SQL_DOUBLE ;b:Sizeof(SQLDOUBLE) ;e: SQL_DOUBLE), + (T:SQL_DATE ;b:Sizeof(SQL_DATE_STRUCT) ;e: SQL_DATE), + (T:SQL_TIME ;b:sizeof(SQL_TIME_STRUCT) ;e: SQL_TIME), + (T:SQL_TIMESTAMP ;b:sizeof(SQL_TIMESTAMP_STRUCT) ;e: SQL_TIMESTAMP), + (T:SQL_VARCHAR ;b:-1 ;e: SQL_CHAR), + (T:SQL_UNKNOWN_TYPE ;b:0 ;e: SQL_UNKNOWN_TYPE), + (T:SQL_LONGVARCHAR ;b:-1 ;e: SQL_CHAR), + (T:SQL_BINARY ;b:-2 ;e: SQL_BINARY), + (T:SQL_VARBINARY ;b:-2 ;e: SQL_BINARY), + (T:SQL_LONGVARBINARY ;b:-2 ;e: SQL_BINARY), + (T:SQL_BIGINT ;b:sizeOf(SQLDOUBLE) ;e: SQL_DOUBLE), + (T:SQL_TINYINT ;b:Sizeof(SQLSMALLINT) ;e: SQL_SMALLINT), + (T:SQL_BIT ;b:sizeof(SQL_CHAR) ;e: SQL_BIT), + (T:SQL_WCHAR ;b:-1 ;e: SQL_CHAR), + (T:SQL_WVARCHAR ;b:-1 ;e: SQL_CHAR), + (T:SQL_WLONGVARCHAR ;b:-1 ;e: SQL_CHAR), + (T:SQL_TYPE_DATE ;b:sizeof(SQL_DATE_STRUCT) ;e: SQL_TYPE_DATE), + (T:SQL_TYPE_TIME ;b:sizeof(SQL_TIME_STRUCT) ;e: SQL_TYPE_TIME), + (T:SQL_TYPE_TIMESTAMP;b:sizeof(SQL_TIMESTAMP_STRUCT) ;e: SQL_TYPE_TIMESTAMP) + ); +{ // template + (T: ;b: ;e: ), +} + +Function GetColSizeBufType (Coltype: SQLSmallint; + Var BufSize : SQLInteger; + Var BufType : SQLSmallInt) : Boolean; +Var + I : Integer; + +begin + I:=0; + BufSize:=0; + BufType:=0; + While (I<=BufDescrCount) and (BufDescr[i].t<>Coltype) do + Inc(i); + Result:=(i<=BufDescrCount); + If Result then + begin + BufSize:=BufDescr[i].b; + BufType:=BufDescr[i].e; + end; +end; + + +procedure TODBCStatement.BindFields(RestrictList : TStrings); + +Var + Count: SQLSmallInt; + CName : Array[0..SQL_NAME_LEN] of Char; + CSize : SQLUINTEGER; + CDataType,CDecimals,CNullable,CNameLen: SQLSmallInt; + I : integer; + +begin + CheckODBC(SQLNumResultCols(Handle,Count),SErrColumnCount); + For I:=1 to Count do + begin + CheckODBC(SQLDescribeCol(Handle,i,CName,SQL_NAME_LEN,CNameLen, + CdataType,CSize, CDecimals,CNullable) + ,SErrColDescription); + If Not Assigned(RestrictList) or (RestrictList.IndexOf(Cname)<>-1) then + With FFields.Add as TODBCField do + begin + FPosition:=I; + FName:=Cname; + FDataType:=CDataType; + FSize:=CSize; + FDecimalDigits:=CDecimals; + FNullable:=(CNullable=SQL_TRUE); + GetColsizeBufType(FDataType,FBufSize,FBufType); + If FBufSize=-1 then + FBufSize:=FSize; + end; + end; + AllocBuffers; + For I:=0 to Count-1 do + With FFields.Items[i] as TODBCField do + CheckODBC(SQLBindCol(Handle,FPosition,FBufType,GetData,FBufSize,FBuffer+FBuffOffset) + ,SErrBindCol); + +end; + +procedure TODBCStatement.ClearFields; +begin + FFields.Clear; +end; + +constructor TODBCStatement.Create(Aowner: TComponent); +begin + FHandleType:=SQL_HANDLE_STMT; + inherited; + If AOwner is TODBCConnection then + Connection:=TODBCConnection(Aowner); + FFields:=TODBCFieldList.Create(Self); +end; + +function TODBCStatement.ParentHandle: SQLHandle; +begin + If (Connection=Nil) then + ODBCError(SErrNoConnectionForStatement); + Result:=Connection.Handle; +end; + +procedure TODBCStatement.SetConnection(const Value: TODBCConnection); +begin + If Value<>FConnection then + begin + If HandleAllocated then + FreeHandle; + FConnection := Value; + end; +end; + +Function TODBCStatement.fetch : Boolean; + +Var + res : SQLReturn; + +begin + Res:=SQLFetch(Handle); + Result:=(Res=SQL_SUCCESS); + If Not Result and (Res<>SQL_NO_DATA) then + CheckODBC(Res,SErrFetchingData); + FBof:=False; + If (Res=SQL_NO_DATA) then + FEOF:=True; +end; + +destructor TODBCStatement.Destroy; +begin + FFields.Free; + inherited; +end; + +{ TODBCSQLStatement } + +procedure TODBCSQLStatement.GetFieldList(List : TStrings); + +Var + Count: SQLSmallInt; + CName : Array[0..SQL_NAME_LEN] of Char; + CSize : SQLUINTEGER; + CDataType,CDecimals,CNullable,CNameLen: SQLSmallInt; + I : integer; + +begin + if Not (FState in [ssPrepared,ssBound,ssOpen]) then + ODBCError(SErrNotPrepared); + List.Clear; + CheckODBC(SQLNumResultCols(Handle,Count),SErrColumnCount); + For I:=1 to Count do + begin + CheckODBC(SQLDescribeCol(Handle,i,CName,SQL_NAME_LEN,CNameLen, + CdataType,CSize, CDecimals,CNullable) + ,SErrColDescription); + List.Add(CName); + end; +end; + + +procedure TODBCSQLStatement.Unprepare; + +begin + Case FState of + ssBound,ssOpen : + begin + ClearFields; + FreeStatement(SQL_CLOSE); + end; + ssPrepared : begin + FreeStatement(SQL_CLOSE); + end; + end; + FState:=ssInactive; +end; + +procedure TODBCSQLStatement.FreeStatement(Option : SQLUSMALLINT); + +begin + SQLFreeStmt(Handle,SQL_CLOSE); +end; + +procedure TODBCSQLStatement.Close; +begin + if FState<>ssInactive then + begin + Unprepare; + FreeStatement(SQL_CLOSE); + FState:=ssInactive; + end; +end; + +constructor TODBCSQLStatement.Create(Aowner: TComponent); +begin + inherited; + FSQL:=TStringList.Create; +end; + +destructor TODBCSQLStatement.Destroy; +begin + if FState=ssOpen then + Close + else If FState<>ssInactive then + Unprepare; + FSQL.Free; + inherited; +end; + +procedure TODBCSQLStatement.ExecSQL; +begin + Case FState of + ssPrepared,ssBound : ExecutePrepared; + ssInactive : ExecuteDirect; + else + Raise Exception.Create(SErrStatementActive) + end; +end; + +procedure TODBCSQLStatement.ExecuteDirect; + +Var + S : String; + +begin + if FState<>ssInactive then + ODBCError(SErrStatementActive); + S:=SQL.Text; + CheckODBC(SQLExecDirect(Handle,PChar(S),SQL_NTS),SErrExecuting); +end; + +procedure TODBCSQLStatement.ExecutePrepared; +begin + if Not (FState in [ssPrepared,ssBound]) then + ODBCError(SErrNotPrepared); + CheckODBC(SQLExecute(Handle),SErrExecutingPrepared); +end; + +function TODBCSQLStatement.GetActive: Boolean; +begin + Result:=(FState=ssOpen); +end; + +procedure TODBCSQLStatement.Open; +begin + if (FState<>ssOpen) then + begin + Writeln('Preparing'); + If FState=ssInactive then + Prepare; + Writeln('Bind fields'); + if FState=ssPrepared then + BindFields(Nil); + Writeln('Executing'); + ExecSQL; + Writeln('Fetching'); + If FState=ssBound then + Fetch; + FState:=ssOpen; + FBOF:=True; + end; +end; + +procedure TODBCSQLStatement.Prepare; + +Var + S : String; + +begin + If FState<>ssInactive then + ODBCError(SErrNotInactive); + If (FSQL.Count=0) then + ODBCError(SErrNoSQLStatement); + S:=FSQL.Text; + CheckODBC(SQLPrepare(Handle,PChar(S),SQL_NTS),SErrPreparing); + FState:=ssPrepared; +end; + +procedure TODBCSQLStatement.SetActive(const Value: Boolean); +begin + If Value then + Open + else + Close; +end; + +procedure TODBCSQLStatement.SetSQL(const Value: TStrings); + +begin + FSQL.Assign(Value); +end; + + +procedure TODBCSQLStatement.BindFields(RestrictList: TStrings); +begin + inherited; + FState:=ssBound; +end; + + +procedure TODBCStatement.AllocBuffers; + +Var + I,TotalSize,AddSize : Integer; + +begin + TotalSize:=0; + For i:=0 to FFields.Count-1 do + With (FFields.Items[i] as TODBCField) do + begin + AddSize:=FBufSize; + If FBufSize=-2 then // Blob. + AddSize:=0 + else if FBufSize=-1 then + AddSize:=FSize+1; // some Char variant. + // Store offset temporarily in FData + FBuffOffset:=TotalSize; + Inc(TotalSize,AddSize+SizeOf(SQLinteger)); + end; + FBuffer:=GetMem(TotalSize); + TotalSize:=0; + For i:=0 to FFields.Count-1 do + With (FFields.Items[i] as TODBCField) do + FBuffer:=Self.FBuffer; +end; + +{ TODBCTableList } + +procedure TODBCTableList.GetTableNames(S: TStrings; SystemTables : Boolean); + +var + TName, + TType: array[0..SQL_NAME_LEN+1] of char; + NL,TL: SQLINTEGER; + Res: SQLRETURN; + +begin + S.Clear; + Res:=CheckODBC(SQLTables(handle, nil,0,nil,0,nil,0,nil,0),SErrGettingTableNames); + if Res=SQL_SUCCESS then + begin + // Must bind by colno, because names changed between ODBC 2.0 and 3.0 !! + SQLBindCol(handle,3,SQL_CHAR,@TName,SQL_NAME_LEN,@NL); + SQLBindCol(handle,4,SQL_CHAR,@TType,SQL_NAME_LEN,@TL); + While Fetch do + if SystemTables or (CompareText(TType,'SYSTEM TABLE')<>0) then + S.Add(TName); + end; +end; + +{ TODBCFieldNamesList } + +procedure TODBCFieldNamesList.GetFieldNames(TableName: String; + S: TStrings); + +var + FName : array[0..SQL_NAME_LEN+1] of char; + NF : SQLINTEGER; + Res: SQLRETURN; + +begin + S.Clear; + Res:=CheckODBC(SQLColumns(handle, nil, 0, nil, 0, pchar(TableName), SQL_NTS, nil, 0),SErrFieldNames); + if Res=SQL_SUCCESS then + begin + SQLBindCol(handle, 4, SQL_CHAR, @FNAme, SQL_NAME_LEN, @NF); + While Fetch do + S.Add(FName); + end; +end; + +{ TODBCPrimaryKeyFieldsList } + +procedure TODBCPrimaryKeyFieldsList.GetPrimaryKeyFields(TableName: String; + S: TStrings); +var + FName : array[0..SQL_NAME_LEN+1] of char; + NF : SQLINTEGER; + Res: SQLRETURN; + +begin + S.Clear; + Res:=CheckODBC(SQLPrimaryKeys(handle, nil, 0, nil, 0, pchar(TableName), SQL_NTS),SErrPrimaryKeys); + if Res=SQL_SUCCESS then + begin + SQLBindCol(handle, 4, SQL_CHAR, @FNAme, SQL_NAME_LEN, @NF); + While Fetch do + S.Add(FName); + end; + +end; + +{ TODBCProcedureList } + +procedure TODBCProcedureList.GetProcedureList(S: TStrings); + +var + PName : array[0..SQL_NAME_LEN+1] of char; + NP : SQLINTEGER; + Res: SQLRETURN; + +begin + S.Clear; + Res:=CheckODBC(SQLProcedures(handle, nil, 0, nil, 0, Nil, 0),SErrProcedureNames); + if Res=SQL_SUCCESS then + begin + SQLBindCol(handle, 3, SQL_CHAR, @PNAme, SQL_NAME_LEN, @NP); + While Fetch do + S.Add(PName); + end; + +end; + +{ TODBCProcedureParams } + +procedure TODBCProcedureParams.GetProcedureParams(ProcName: String; + ParamTypes: TODBCParamTypes; S: TStrings); + +var + PName : array[0..SQL_NAME_LEN+1] of char; + NP,NT : SQLINTEGER; + Ptype : SQLSmallInt; + Res: SQLRETURN; + +begin + S.Clear; + Res:=CheckODBC(SQLProcedureColumns(handle, nil, 0, nil, 0, PChar(ProcName),SQL_NTS,Nil, 0),SErrProcedureNames); + if Res=SQL_SUCCESS then + begin + SQLBindCol(handle, 4, SQL_CHAR, @PName, SQL_NAME_LEN, @NP); + SQLBindCol(handle, 5, SQL_SMALLINT, @PType, SizeOf(SQLSmallInt), @NT); + While Fetch do + begin + If TODBCParamType(PType) in ParamTypes then + S.Add(PName); + end; + end; +end; + +{ TODBCFieldList } + +constructor TODBCFieldList.Create(Statement: TODBCStatement); +begin + FStatement:=Statement; + Inherited Create(TODBCField); +end; + +{ TODBCField } + +function TODBCField.GetAsString: String; +begin + If IsNull then + Result:='' + else + Case FBufType of + SQL_Smallint : Result:=IntToStr(PSQLSmallInt(Data)^); + SQL_Integer : Result:=IntToStr(PSQLINTEGER(Data)^); + SQL_BIT : Result:=IntToStr(PByte(Data)^); + SQL_CHAR : Result:=StrPas(Data); + SQL_DOUBLE : Result:=FloatToStr(GetAsDouble); + SQL_DATE : result:=DateToStr(AsDateTime); + SQL_TIME : Result:=TimeToStr(AsDateTime); + SQL_TIMESTAMP : result:=datetimeToStr(AsDateTime); + SQL_TYPE_DATE : result:=dateToStr(AsDateTime); + SQL_TYPE_TIMESTAMP : result:=datetimeToStr(AsDateTime); + SQL_TYPE_TIME : Result:=TimeToStr(AsDateTime); + else + ODBCError(SErrInvalidConversion) + end; +end; + +function TODBCField.GetData : Pchar; + +begin + Result:=FBuffer+FBuffOffset+SizeOf(SQLinteger); +end; + +function TODBCField.GetIsNull : boolean; + +begin + Result:=PSQLinteger(FBuffer+FBuffOffset)^=SQL_NULL_DATA; +end; + +Function TODBCField.GetAsInteger : Integer; + +begin + If IsNull then + Result:=0 + else + Case FBufType of + SQL_Smallint : Result:=PSQLSmallInt(Data)^; + SQL_Integer : Result:=PSQLINTEGER(Data)^; + SQL_BIT : Result:=PByte(Data)^; + SQL_CHAR : Result:=StrToInt(GetAsString); + SQL_DOUBLE : Result:=Round(GetAsDouble); + SQL_DATE, + SQL_TIME, + SQL_TIMESTAMP, + SQL_TYPE_DATE, + SQL_TYPE_TIMESTAMP, + SQL_TYPE_TIME : Result:=Round(AsDateTime); + else + ODBCError(SErrInvalidConversion) + end; +end; + +Function TODBCField.GetAsBoolean : Boolean; + +begin + If IsNull then + Result:=False + else + Case FBufType of + SQL_Smallint : Result:=PSQLSmallInt(Data)^=0; + SQL_Integer : Result:=PSQLINTEGER(Data)^=0; + SQL_BIT : Result:=PBYTE(Data)^=0; + SQL_CHAR : Result:=(StrToInt(GetAsString)=0); + SQL_DOUBLE : Result:=Round(GetAsDouble)=0; + SQL_DATE, + SQL_TIME, + SQL_TIMESTAMP, + SQL_TYPE_DATE, + SQL_TYPE_TIMESTAMP, + SQL_TYPE_TIME : Result:=Round(AsDateTime)=0; + else + ODBCError(SErrInvalidConversion) + end; +end; + +Function TODBCField.GetAsDouble : Double; + +begin + If IsNull then + Result:=0 + else + Case FBufType of + SQL_Smallint : Result:=PSQLSmallInt(Data)^; + SQL_Integer : Result:=PSQLINTEGER(Data)^; + SQL_BIT : Result:=PBYTE(Data)^; + SQL_CHAR : Result:=StrToFloat(GetAsString); + SQL_DOUBLE : Result:=PSQLDOUBLE(GetData)^; + SQL_DATE, + SQL_TIME, + SQL_TIMESTAMP, + SQL_TYPE_DATE, + SQL_TYPE_TIMESTAMP, + SQL_TYPE_TIME : Result:=AsDateTime; + else + ODBCError(SErrInvalidConversion) + end; +end; + +{ +function DateStructToDateTime( b:PSQL_DATE_STRUCT):TDateTime; +function DateTimeToDateStruct( b:TDateTime):SQL_DATE_STRUCT; +procedure DateTime2TimeStampStruct( var Value:SQL_TIMESTAMP_STRUCT; b:TDateTime); +} +Function TODBCField.GetAsDateTime : TDateTime; + +begin + If IsNull then + Result:=0 + else + Case FBufType of + SQL_Smallint : Result:=PSQLSmallInt(Data)^; + SQL_Integer : Result:=PSQLINTEGER(Data)^; + SQL_BIT : Result:=PBYTE(Data)^; + SQL_CHAR : Result:=StrToInt(GetAsString); + SQL_DOUBLE : Result:=PSQLDOUBLE(GetData)^; + SQL_DATE : Result:=DateStructToDateTime(PSQL_DATE_STRUCT(Data)); + SQL_TIME : Result:=TimeStructToDateTime(PSQL_TIME_STRUCT(Data)); + SQL_TIMESTAMP : Result:=TimeStampStructToDateTime(PSQL_TIMESTAMP_STRUCT(Data)); + SQL_TYPE_DATE : Result:=DateStructToDateTime(PSQL_DATE_STRUCT(Data)); + SQL_TYPE_TIMESTAMP : Result:=TimeStampStructToDateTime(PSQL_TIMESTAMP_STRUCT(Data)); + SQL_TYPE_TIME : Result:=TimeStructToDateTime(PSQL_TIME_STRUCT(Data)); + else + ODBCError(SErrInvalidConversion) + end; +end; + +Finalization + If Assigned(DefEnv) then + TODBCEnvironment(DefEnv).Free; +end. + diff --git a/fcl/db/odbc/testbcon.pp b/fcl/db/odbc/testbcon.pp new file mode 100644 index 0000000000..21c6720f8b --- /dev/null +++ b/fcl/db/odbc/testbcon.pp @@ -0,0 +1,63 @@ +program testbcon; +{ + Test browsingconnection + - I don't have a driver which supports it though :/ +} +{$mode objfpc} +uses fpodbc,Classes; + +Type + TApp = Class (TObject) + Conn : TODBCConnection; + Procedure GetParams (Sender : TObject; ListIn,ListOut : TStrings); + Procedure Run; + end; + + +{ TApp } + +procedure TApp.GetParams(Sender: TObject; ListIn, ListOut: TStrings); + +Var + S : String; + i : integer; + +begin + Writeln('Input parameters were :'); + With ListIN do + For I:=0 to Count-1 do + Writeln(Strings[i]); + Writeln('Output parameters were :'); + With Listout do + For I:=0 to Count-1 do + Writeln(Strings[i]); + Repeat + Writeln('Parameter to add to input (empty to quit):'); + Readln(S); + If S<>'' then + ListIn.Add(S) + Until S=''; +end; + +procedure TApp.Run; +begin + Conn:=TODBCConnection.Create(Nil); + Try + Conn.DSN:='FPC'; + Conn.OnBrowseConnection:=@Self.GetParams; + Conn.Active:=True; + Writeln('Connected !!'); + Conn.Active:=False; + Finally + Conn.free; + end; +end; + +begin + With Tapp.Create do + Try + Run; + Finally + Free; + end; +end. \ No newline at end of file diff --git a/fcl/db/odbc/testcon.pp b/fcl/db/odbc/testcon.pp new file mode 100644 index 0000000000..0bc162d8cc --- /dev/null +++ b/fcl/db/odbc/testcon.pp @@ -0,0 +1,19 @@ +program testcon; +{$mode objfpc} +uses fpodbc,Classes; + +var + Conn : TODBCConnection; + +begin + Conn:=TODBCConnection.Create(Nil); + Try + Conn.DSN:='FPC'; + Conn.Active:=True; + Writeln('Connected !!'); + Conn.Active:=False; + Writeln('Disconnected again'); + Finally + Conn.free; + end; +end. diff --git a/fcl/db/odbc/testdrcon.pp b/fcl/db/odbc/testdrcon.pp new file mode 100644 index 0000000000..246598805d --- /dev/null +++ b/fcl/db/odbc/testdrcon.pp @@ -0,0 +1,20 @@ +program testdrcon; +{$mode objfpc} +uses fpodbc,Classes; + +var + Conn : TODBCConnection; + +begin + Conn:=TODBCConnection.Create(Nil); + Try + Conn.drivername:='Microsoft Access Driver (*.mdb)'; + Conn.DriverParams.Add('DBQ=d:\temp\odbc\testodbc.mdb'); + Conn.Active:=True; + Writeln('Connected !!'); + Conn.Active:=False; + Writeln('Disconnected again.'); + Finally + Conn.free; + end; +end. diff --git a/fcl/db/odbc/testenv.pp b/fcl/db/odbc/testenv.pp new file mode 100644 index 0000000000..d7e3c26874 --- /dev/null +++ b/fcl/db/odbc/testenv.pp @@ -0,0 +1,45 @@ +program testenv; +{$mode objfpc} +{$h+} +uses fpodbc,Classes; + +Var + I,J : Integer; + List,Options : TStringList; + Env : TODBCEnvironment; + UseDefault : Boolean; + +begin + useDefault:=(ParamCount>0) and (Paramstr(1)='-d'); + If UseDefault then + Env:=DefaultEnvironment + else + Env:=TODBCEnvironment.Create(Nil); + try + Writeln('Handle is : ',Env.Handle); + List:=TStringlist.Create; + Options:=TStringList.Create; + Writeln('List of drivers :'); + Env.GetDriverNames(List); + Writeln('Count : ',List.Count); + For I:=0 to List.Count-1 do + Writeln(i:2,' : ',List[i]); + Writeln('List of driver options :'); + For I:=0 to List.Count-1 do + begin + Env.GetDriverOptions(List[i],Options); + Writeln('Options for driver ',List[i],' : '); + For J:=0 to Options.Count-1 do + Writeln(' ',Options[j]); + end; + Env.GetDataSourceNames(List,dtBoth,True); + Writeln('List of datasource names : '); + For I:=0 to List.Count-1 do + writeln(i,' : ',List[i]); + List.free; + options.Free; + finally + If not UseDefault then + env.free; + end; +end. \ No newline at end of file diff --git a/fcl/db/odbc/testfl.pp b/fcl/db/odbc/testfl.pp new file mode 100644 index 0000000000..da5cd114a5 --- /dev/null +++ b/fcl/db/odbc/testfl.pp @@ -0,0 +1,29 @@ +program testfl; +{$mode objfpc} +uses fpodbc,Classes; + +var + Conn : TODBCConnection; + FieldNames : TStringList; + I : Integer; + +begin + Conn:=TODBCConnection.Create(Nil); + Try + Conn.DSN:='FPC'; + Conn.Active:=True; + FieldNames:=TStringList.Create; + FieldNames.Sorted:=True; + Try + Conn.GetFieldNames('FPDev',FieldNames); + Writeln('Found ',FieldNames.Count,' Fields in table FPDev : '); + For I:=0 to FieldNames.Count-1 do + Writeln(FieldNames[i]); + finally + FieldNames.Free; + end; + Conn.Active:=False; + Finally + Conn.free; + end; +end. diff --git a/fcl/db/odbc/testodbc.mdb b/fcl/db/odbc/testodbc.mdb new file mode 100644 index 0000000000000000000000000000000000000000..d1ed5d743dd98e85cd298e8189f36de12f08fc09 GIT binary patch literal 81920 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