* Added ms-sql server connector by LaCak2

git-svn-id: trunk@20522 -
This commit is contained in:
michael 2012-03-16 08:36:12 +00:00
parent 639aa0c0c2
commit 5331e66a8d
14 changed files with 6780 additions and 437 deletions

10
.gitattributes vendored
View File

@ -1618,6 +1618,10 @@ packages/cocoaint/utils/uikit-skel/src/opengles/OpenGLES.inc svneol=native#text/
packages/cocoaint/utils/uikit-skel/src/patches/NSObjCRuntime.patch svneol=native#text/plain
packages/cocoaint/utils/uikit-skel/src/quartzcore/QuartzCore.inc svneol=native#text/plain
packages/cocoaint/utils/uikit-skel/src/uikit/UIKit.inc svneol=native#text/plain
packages/dblib/Makefile svneol=native#text/plain
packages/dblib/Makefile.fpc svneol=native#text/plain
packages/dblib/fpmake.pp svneol=native#text/plain
packages/dblib/src/dblib.pp svneol=native#text/plain
packages/dbus/Makefile svneol=native#text/plain
packages/dbus/Makefile.fpc svneol=native#text/plain
packages/dbus/Makefile.fpc.fpcmake svneol=native#text/plain
@ -1958,6 +1962,12 @@ packages/fcl-db/src/sqldb/interbase/Makefile.fpc svneol=native#text/plain
packages/fcl-db/src/sqldb/interbase/fpmake.inc svneol=native#text/plain
packages/fcl-db/src/sqldb/interbase/fpmake.pp svneol=native#text/plain
packages/fcl-db/src/sqldb/interbase/ibconnection.pp svneol=native#text/plain
packages/fcl-db/src/sqldb/mssql/Makefile svneol=native#text/plain
packages/fcl-db/src/sqldb/mssql/Makefile.fpc svneol=native#text/plain
packages/fcl-db/src/sqldb/mssql/fpmake.inc svneol=native#text/plain
packages/fcl-db/src/sqldb/mssql/fpmake.pp svneol=native#text/plain
packages/fcl-db/src/sqldb/mssql/mssqlconn.pp svneol=native#text/plain
packages/fcl-db/src/sqldb/mssql/readme.txt svneol=native#text/plain
packages/fcl-db/src/sqldb/mysql/Makefile svneol=native#text/plain
packages/fcl-db/src/sqldb/mysql/Makefile.fpc svneol=native#text/plain
packages/fcl-db/src/sqldb/mysql/fpmake.inc svneol=native#text/plain

2160
packages/dblib/Makefile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
#
# Makefile.fpc for running fpmake
#
[package]
name=dblib
version=2.7.1
[require]
packages=rtl fpmkunit
[install]
fpcpackage=y
[default]
fpcdir=../..
[prerules]
FPMAKE_BIN_CLEAN=$(wildcard .$(PATHSEP)fpmake$(SRCEXEEXT))
ifdef OS_TARGET
FPC_TARGETOPT+=--os=$(OS_TARGET)
endif
ifdef CPU_TARGET
FPC_TARGETOPT+=--cpu=$(CPU_TARGET)
endif
LOCALFPMAKE=.$(PATHSEP)fpmake$(SRCEXEEXT)
[rules]
.NOTPARALLEL:
fpmake: fpmake.pp
$(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT)
all: fpmake
$(LOCALFPMAKE) compile --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC) -bu
smart: fpmake
$(LOCALFPMAKE) compile --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC) -bu -o -XX -o -CX
release: fpmake
$(LOCALFPMAKE) compile --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC) -bu -o -dRELEASE
debug: fpmake
$(LOCALFPMAKE) compile --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC) -bu -o -dDEBUG
# If no fpmake exists and (dist)clean is called, do not try to build fpmake, it will
# most often fail because the dependencies are cleared.
# In case of a clean, simply do nothing
ifeq ($(FPMAKE_BIN_CLEAN),)
clean:
else
clean:
$(FPMAKE_BIN_CLEAN) clean --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC)
endif
# In case of a distclean, perform an 'old'-style distclean. This to avoid problems
# when the package is compiled using fpcmake prior to running this clean using fpmake
ifeq ($(FPMAKE_BIN_CLEAN),)
distclean: $(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall
else
distclean:
ifdef inUnix
{ $(FPMAKE_BIN_CLEAN) distclean --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi; }
else
$(FPMAKE_BIN_CLEAN) distclean --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC)
endif
-$(DEL) $(LOCALFPMAKE)
endif
install: fpmake
ifdef UNIXHier
$(LOCALFPMAKE) install --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR)
else
$(LOCALFPMAKE) install --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC) --prefix=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR)
endif
# distinstall also installs the example-sources
distinstall: fpmake
ifdef UNIXHier
$(LOCALFPMAKE) install --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie
else
$(LOCALFPMAKE) install --localunitdir=../.. --globalunitdir=.. $(FPC_TARGETOPT) $(addprefix -o ,$(FPCOPT)) --compiler=$(FPC) --prefix=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie
endif

39
packages/dblib/fpmake.pp Normal file
View File

@ -0,0 +1,39 @@
{$ifndef ALLPACKAGES}
{$mode objfpc}{$H+}
program fpmake;
uses fpmkunit;
Const
DBLibOSes = [linux,freebsd,netbsd,openbsd,win32];
Var
P : TPackage;
T : TTarget;
begin
With Installer do
begin
{$endif ALLPACKAGES}
P:=AddPackage('dblib');
{$ifdef ALLPACKAGES}
P.Directory:='dblib';
{$endif ALLPACKAGES}
P.Version:='1.0';
P.Author := 'Library: (FreeTDS/Microsoft), header: Lacack2';
P.License := 'Library: FreeTDS License, header: LGPL with modification, ';
P.HomepageURL := 'www.freepascal.org';
P.Email := '';
P.Description := 'Headers for the MS SQL Server RDBMS';
P.NeedLibC:= true; // true for headers that indirectly link to libc?
P.SourcePath.Add('src');
P.IncludePath.Add('src');
T:=P.Targets.AddUnit('dblib.pp',DBLibOSes);
{$ifndef ALLPACKAGES}
Run;
end;
end.
{$endif ALLPACKAGES}

594
packages/dblib/src/dblib.pp Normal file
View File

@ -0,0 +1,594 @@
{
This file is part of the Free Component Library (FCL)
Copyright (c) 2010 by the Free Pascal development team
Header files Microsoft DB-Library for C: sqlfront.h, sqldb.h
and FreeTDS: sybdb.h
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
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.
The Original Code was created by (c) 2010 Ladislav Karrach (Windows)
for the Free Pascal project.
**********************************************************************
FreeTDS (http://www.freetds.org/userguide/choosingtdsprotocol.htm):
tds version = 5.0 - Sybase System 10 and above
7.0 - MS SQL Server 7
7.1 - MS SQL Server 2000 (*default*)
7.2 - MS SQL Server 2005
7.3 - MS SQL Server 2008
tds version can be set using env.var. TDSVER or in freetds.conf or .freetds.conf
}
unit dblib;
{$IFDEF FPC}{$mode objfpc}{$ENDIF}{$H+}
{ $DEFINE ntwdblib} //if you are using MS SQL Server Client Library (ntwdblib.dll)
{$IFNDEF ntwdblib}
{$DEFINE freetds} //if you are using db-lib from FreeTDS project (MS SQL Server + Sybase support)
{$ENDIF}
{$DEFINE LOAD_DYNAMICALLY}
interface
const
DBLIBDLL=
{$IFDEF WINDOWS}
{$IFDEF ntwdblib}'ntwdblib.dll'{$ENDIF}
{$IFDEF freetds} 'dblib.dll' {$ENDIF}
{$ELSE}
'libsybdb.so'
{$ENDIF}
;
//from sybdb.h:
//DBVERSION_xxx are used with dbsetlversion()
DBVERSION_100= 2; // Sybase TDS 5.0
DBVERSION_42 = 3; // This can be used for old Microsoft and Sybase servers
DBVERSION_70 = 4;
DBVERSION_71 = 5;
DBVERSION_72 = 6;
DBVERSION_73 = 7;
//DBTDS_xxx are returned by DBTDS()
DBTDS_UNKNOWN= 0;
DBTDS_42 = 4; // SQL Server 4.2
DBTDS_50 = 7; // Sybase SQL Server 5.0; use this for connecting to Sybase (ASA or ASE)
DBTDS_70 = 8; // Microsoft SQL Server 7.0
DBTDS_71 = 9; // Microsoft SQL Server 2000
DBTDS_72 = 10; // Microsoft SQL Server 2005
DBTDS_73 = 11; // Microsoft SQL Server 2008
//from sqlfront.h:
DBSETHOST=1;
DBSETUSER=2;
DBSETPWD=3;
DBSETAPP=4;
DBSETID=5;
DBSETLANG=6;
DBSETSECURE=7;
//These two are defined by Microsoft for dbsetlversion():
DBVER42={$IFDEF freetds}DBVERSION_42{$ELSE}8{$ENDIF};
DBVER60={$IFDEF freetds}DBVERSION_71{$ELSE}9{$ENDIF};
DBSET_LOGINTIME=10;
DBSETFALLBACK=12;
//dboptions:
DBNOAUTOFREE = {$IFDEF freetds}15{$ELSE}8{$ENDIF};
DBTEXTLIMIT = {$IFDEF freetds}7{$ELSE}4{$ENDIF};
DBTEXTSIZE = {$IFDEF freetds}17{$ELSE}5{$ENDIF};
DBANSItoOEM = 14;
DBOEMtoANSI = 15;
DBQUOTEDIDENT= {$IFDEF freetds}35{$ELSE}18{$ENDIF};
TIMEOUT_IGNORE=-1;
TIMEOUT_INFINITE=0;
SUCCEED=1;
FAIL=0;
NO_MORE_RESULTS=2;
NO_MORE_RPC_RESULTS=3;
MORE_ROWS=-1;
REG_ROW=MORE_ROWS;
NO_MORE_ROWS=-2;
BUF_FULL=-3; //only if buffering is turned on
INT_EXIT=0;
INT_CONTINUE=1;
INT_CANCEL=2;
SQLVOID=$1f;
SQLTEXT=$23;
SQLVARBINARY=$25;
SQLINTN=$26; //all nullable integers
SQLVARCHAR=$27;
SQLBINARY=$2d;
SQLIMAGE=$22;
SQLCHAR=$2f;
SQLINT1=$30;
SQLBIT=$32;
SQLINT2=$34;
SQLINT4=$38;
SQLMONEY=$3c;
SQLDATETIME=$3d;
SQLFLT8=$3e;
SQLFLTN=$6d;
SQLMONEYN=$6e;
SQLDATETIMN=$6f;
SQLFLT4=$3b;
SQLMONEY4=$7a;
SQLDATETIM4=$3a;
SQLDECIMAL=$6a;
SQLNUMERIC=$6c;
//from tds.h:
SYBNTEXT=$63;
SYBINT8=$7F;
SYBUNIQUE=$24;
//XSYBVARCHAR=$A7;
//XSYBNVARCHAR=$E7;
//XSYBNCHAR = $EF;
//XSYBBINARY= $AD;
MAXTABLENAME ={$IFDEF freetds}512+1{$ELSE}30{$ENDIF};
MAXCOLNAMELEN={$IFDEF freetds}512+1{$ELSE}30{$ENDIF};
MAXNUMERICLEN={$IFDEF freetds}32 {$ELSE}16{$ENDIF};
DBMAXCHAR=256; // Max length of DBVARBINARY and DBVARCHAR, etc.
DEFAULTPRECISION = 18;
DEFAULTSCALE = 0;
// Used by dbcolinfo:
CI_REGULAR=1;
CI_ALTERNATE=2;
CI_CURSOR=3;
DBUNKNOWN = 2; //FALSE = 0, TRUE = 1
type
PLOGINREC=Pointer;
PDBPROCESS=Pointer;
RETCODE=integer;
STATUS=integer;
INT=longint;
SHORT=smallint;
BOOL=longbool;
ULONG=longword;
// DB-Library datatypes
DBCHAR=char;
DBTINYINT=byte;
DBSMALLINT=smallint;
DBINT=longint;
DBUSMALLINT=word;
DBFLT8=double;
DBBIT=byte;
DBBINARY=byte;
{$PACKRECORDS C}
DBDATETIME=packed record
dtdays: DBINT;
dttime: ULONG;
end;
PDBDATETIME=^DBDATETIME;
// DBDATEREC structure used by dbdatecrack
DBDATEREC=packed record
case boolean of
false:(
oldyear:INT; // 1753 - 9999
oldmonth: INT; // 1 - 12
oldday: INT; // 1 - 31
olddayofyear: INT; // 1 - 366 (in sybdb.h dayofyear and day are changed around!)
oldweekday: INT; // 1 - 7 (Mon - Sun)
oldhour: INT; // 0 - 23
oldminute: INT; // 0 - 59
oldsecond: INT; // 0 - 59
oldmillisecond: INT; // 0 - 999
oldtzone: INT; // 0 - 127 (Sybase only!)
);
true:(
year:INT; // 1753 - 9999
quarter:INT; // 1 - 4
month: INT; // 1 - 12
{$IFDEF freetds}
day: INT; // 1 - 31
dayofyear: INT; // 1 - 366 (in sybdb.h dayofyear and day are changed around!)
{$ELSE}
dayofyear: INT; // 1 - 366 (in sybdb.h dayofyear and day are changed around!)
day: INT; // 1 - 31
{$ENDIF}
week: INT; // 1 - 54 (for leap years)
weekday: INT; // 1 - 7 (Mon - Sun)
hour: INT; // 0 - 23
minute: INT; // 0 - 59
second: INT; // 0 - 59
millisecond: INT; // 0 - 999
tzone: INT; // 0 - 127 (Sybase only!)
);
end;
PDBDATEREC=^DBDATEREC;
DBNUMERIC=packed record
precision: BYTE;
scale: BYTE;
sign: BYTE; // 1 = Positive, 0 = Negative
val: array[0..MAXNUMERICLEN-1] of BYTE;
end;
DBVARYBIN=packed record
len: {$IFDEF freetds}DBINT{$ELSE}DBSMALLINT{$ENDIF};
bytes: array[0..DBMAXCHAR-1] of BYTE;
end;
DBVARYCHAR=packed record
len: {$IFDEF freetds}DBINT{$ELSE}DBSMALLINT{$ENDIF};
str: array[0..DBMAXCHAR-1] of CHAR;
end;
DBERRHANDLE_PROC=function(dbproc: PDBPROCESS; severity, dberr, oserr:INT; dberrstr, oserrstr:PChar):INT; cdecl;
DBMSGHANDLE_PROC=function(dbproc: PDBPROCESS; msgno: DBINT; msgstate, severity:INT; msgtext, srvname, procname:PChar; line:DBUSMALLINT):INT; cdecl;
{$IFDEF ntwdblib}
{$PACKRECORDS 2}
{$ENDIF}
DBCOL=record
SizeOfStruct: DBINT;
Name: array[0..MAXCOLNAMELEN] of char;
ActualName: array[0..MAXCOLNAMELEN] of char;
TableName: array[0..MAXTABLENAME] of char;
Typ: SHORT;
UserType: DBINT;
MaxLength: DBINT;
Precision: BYTE;
Scale: BYTE;
VarLength: BOOL; // TRUE, FALSE
Null: BYTE; // TRUE, FALSE or DBUNKNOWN
CaseSensitive: BYTE; // TRUE, FALSE or DBUNKNOWN
Updatable: BYTE; // TRUE, FALSE or DBUNKNOWN
Identity: BOOL; // TRUE, FALSE
end;
PDBCOL=^DBCOL;
{$PACKRECORDS DEFAULT}
var
DBLibInit: boolean=false; //was dbinit() already called ?
{$IFNDEF LOAD_DYNAMICALLY}
function dbinit():{$IFDEF freetds}RETCODE{$ELSE}PChar{$ENDIF}; cdecl; external DBLIBDLL;
function dblogin():PLOGINREC; cdecl; external DBLIBDLL;
function dbsetlname(login:PLOGINREC; value:PChar; which:INT):RETCODE; cdecl; external DBLIBDLL;
function dbsetlogintime(seconds:INT):RETCODE; cdecl; external DBLIBDLL;
function dbsettime(seconds:INT):RETCODE; cdecl; external DBLIBDLL;
function dberrhandle(handler:DBERRHANDLE_PROC):DBERRHANDLE_PROC; cdecl; external DBLIBDLL;
function dbmsghandle(handler:DBMSGHANDLE_PROC):DBMSGHANDLE_PROC; cdecl; external DBLIBDLL;
function dbsetopt(dbproc:PDBPROCESS; option: INT; param:PChar {$IFDEF freetds};int_param:INT{$ENDIF}):RETCODE; cdecl; external DBLIBDLL;
function dbuse(dbproc:PDBPROCESS; dbname:PChar):RETCODE; cdecl; external DBLIBDLL;
function dbcmd(dbproc:PDBPROCESS; cmdstring:PChar):RETCODE; cdecl; external DBLIBDLL;
function dbcmdrow(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
function dbsqlexec(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
function dbresults(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
function dbmorecmds(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
function dbnextrow(dbproc:PDBPROCESS):STATUS; cdecl; external DBLIBDLL;
function dbnumcols(dbproc:PDBPROCESS):INT; cdecl; external DBLIBDLL;
function dbcolname(dbproc:PDBPROCESS; column:INT):PChar; cdecl; external DBLIBDLL;
function dbcoltype(dbproc:PDBPROCESS; column:INT):INT; cdecl; external DBLIBDLL;
function dbcollen(dbproc:PDBPROCESS; column:INT):DBINT; cdecl; external DBLIBDLL;
function dbcolinfo(dbproc:PDBPROCESS; typ:INT; column:DBINT; computeid:DBINT; dbcol:PDBCOL):RETCODE; cdecl; external DBLIBDLL;
function dbprtype(token:INT):PChar; cdecl; external DBLIBDLL;
function dbdatlen(dbproc:PDBPROCESS; column:INT):DBINT; cdecl; external DBLIBDLL;
function dbdata(dbproc:PDBPROCESS; column:INT):PByte; cdecl; external DBLIBDLL;
function dbconvert(dbproc:PDBPROCESS; srctype:INT; src:PByte; srclen:DBINT; desttype:INT; dest:PByte; destlen:DBINT):INT; cdecl; external DBLIBDLL;
function dbdatecrack(dbproc:PDBPROCESS; dateinfo:PDBDATEREC; datetime: PDBDATETIME):RETCODE; cdecl; external DBLIBDLL;
function dbcount(dbproc:PDBPROCESS):DBINT; cdecl; external DBLIBDLL;
function dbiscount(dbproc:PDBPROCESS):BOOL; cdecl; external DBLIBDLL;
function dbcancel(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
function dbcanquery(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
procedure dbfreelogin(login:PLOGINREC); cdecl; external DBLIBDLL {$IFDEF freetds}name 'dbloginfree'{$ENDIF};
procedure dbexit(); cdecl; external DBLIBDLL;
{$IFDEF ntwdblib}
function dbopen(login:PLOGINREC; servername:PChar):PDBPROCESS; cdecl; external DBLIBDLL;
function dbclose(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
procedure dbwinexit; cdecl; external DBLIBDLL;
{$ENDIF}
{$IFDEF freetds}
function tdsdbopen(login:PLOGINREC; servername:PChar; msdblib:INT):PDBPROCESS; cdecl; external DBLIBDLL;
function dbtablecolinfo(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE; cdecl; external DBLIBDLL;
function dbtds(dbproc:PDBPROCESS):INT; cdecl; external DBLIBDLL;
function dbsetlversion(login:PLOGINREC; version:BYTE):RETCODE; cdecl; external DBLIBDLL;
function dbservcharset(dbproc:PDBPROCESS):PChar; cdecl; external DBLIBDLL;
procedure dbclose(dbproc:PDBPROCESS); cdecl; external DBLIBDLL;
{$ENDIF}
{$ELSE}
var
dbinit: function():{$IFDEF freetds}RETCODE{$ELSE}PChar{$ENDIF}; cdecl;
dblogin: function():PLOGINREC; cdecl;
dbsetlname: function(login:PLOGINREC; value:PChar; which:INT):RETCODE; cdecl;
dbsetlogintime: function(seconds:INT):RETCODE; cdecl;
dbsettime: function(seconds:INT):RETCODE; cdecl;
dberrhandle: function(handler:DBERRHANDLE_PROC):DBERRHANDLE_PROC; cdecl;
dbmsghandle: function(handler:DBMSGHANDLE_PROC):DBMSGHANDLE_PROC; cdecl;
dbsetopt: function(dbproc:PDBPROCESS; option: INT; param:PChar {$IFDEF freetds};int_param:INT{$ENDIF}):RETCODE; cdecl;
dbuse: function(dbproc:PDBPROCESS; dbname:PChar):RETCODE; cdecl;
dbcmd: function(dbproc:PDBPROCESS; cmdstring:PChar):RETCODE; cdecl;
dbcmdrow: function(dbproc:PDBPROCESS):RETCODE; cdecl;
dbsqlexec: function(dbproc:PDBPROCESS):RETCODE; cdecl;
dbresults: function(dbproc:PDBPROCESS):RETCODE; cdecl;
dbmorecmds: function(dbproc:PDBPROCESS):RETCODE; cdecl;
dbnextrow: function(dbproc:PDBPROCESS):STATUS; cdecl;
dbnumcols: function(dbproc:PDBPROCESS):INT; cdecl;
dbcolname: function(dbproc:PDBPROCESS; column:INT):PChar; cdecl;
dbcoltype: function(dbproc:PDBPROCESS; column:INT):INT; cdecl;
dbcollen: function(dbproc:PDBPROCESS; column:INT):DBINT; cdecl;
dbcolinfo: function(dbproc:PDBPROCESS; typ:INT; column:DBINT; computeid:DBINT; dbcol:PDBCOL):RETCODE; cdecl;
dbprtype: function(token:INT):PChar; cdecl;
dbdatlen: function(dbproc:PDBPROCESS; column:INT):DBINT; cdecl;
dbdata: function(dbproc:PDBPROCESS; column:INT):PByte; cdecl;
dbconvert: function(dbproc:PDBPROCESS; srctype:INT; src:PByte; srclen:DBINT; desttype:INT; dest:PByte; destlen:DBINT):INT; cdecl;
dbdatecrack: function(dbproc:PDBPROCESS; dateinfo:PDBDATEREC; datetime: PDBDATETIME):RETCODE; cdecl;
dbcount: function(dbproc:PDBPROCESS):DBINT; cdecl;
dbiscount: function(dbproc:PDBPROCESS):BOOL; cdecl;
dbcancel: function(dbproc:PDBPROCESS):RETCODE; cdecl;
dbcanquery: function(dbproc:PDBPROCESS):RETCODE; cdecl;
dbexit: procedure(); cdecl;
dbfreelogin: procedure(login:PLOGINREC); cdecl;
{$IFDEF ntwdblib}
dbopen: function(login:PLOGINREC; servername:PChar):PDBPROCESS; cdecl;
dbclose: function(dbproc:PDBPROCESS):RETCODE; cdecl;
dbwinexit: procedure; cdecl;
{$ENDIF}
{$IFDEF freetds}
tdsdbopen: function(login:PLOGINREC; servername:PChar; msdblib:INT):PDBPROCESS; cdecl;
dbtablecolinfo: function(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE; cdecl;
dbtds: function(dbproc:PDBPROCESS):INT; cdecl;
dbsetlversion: function(login:PLOGINREC; version:BYTE):RETCODE; cdecl;
dbservcharset: function(dbproc:PDBPROCESS):PChar; cdecl;
dbclose: procedure(dbproc:PDBPROCESS); cdecl;
{$ENDIF}
DefaultDBLibLibraryName: String = DBLIBDLL;
{$ENDIF}
{$IFDEF ntwdblib}
function tdsdbopen(login:PLOGINREC; servername:PChar; msdblib:INT):PDBPROCESS;
function dbtablecolinfo(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE;
function dbsetlversion(login:PLOGINREC; version:BYTE):RETCODE;
function dbtds(dbproc:PDBPROCESS):INT;
function dbversion():PChar;
{$ENDIF}
{$IFDEF freetds}
function dbopen(login:PLOGINREC; servername:PChar):PDBPROCESS;
procedure dbwinexit;
{$ENDIF}
function dbsetlcharset(login:PLOGINREC; charset:PChar):RETCODE;
function dbsetlsecure(login:PLOGINREC):RETCODE;
procedure InitialiseDBLib(LibraryName : string = '');
procedure ReleaseDBLib;
implementation
{$IFDEF LOAD_DYNAMICALLY}
uses SysUtils, Dynlibs;
var DBLibLibraryHandle: TLibHandle;
RefCount: integer;
procedure InitialiseDBLib(LibraryName : string);
var libname : string;
begin
inc(RefCount);
if RefCount = 1 then
begin
if LibraryName='' then
libname:=DefaultDBLibLibraryName
else
libname:=LibraryName;
DBLibLibraryHandle := LoadLibrary(libname);
if DBLibLibraryHandle = nilhandle then
begin
RefCount := 0;
raise EInOutError.CreateFmt('Can not load DB-Lib client library "%s". Check your installation.'#13'%s',
[libname, SysErrorMessage(GetLastOSError)]);
end;
pointer(dbinit) := GetProcedureAddress(DBLibLibraryHandle,'dbinit');
pointer(dblogin) := GetProcedureAddress(DBLibLibraryHandle,'dblogin');
pointer(dbsetlname) := GetProcedureAddress(DBLibLibraryHandle,'dbsetlname');
pointer(dbsetlogintime) := GetProcedureAddress(DBLibLibraryHandle,'dbsetlogintime');
pointer(dbsettime) := GetProcedureAddress(DBLibLibraryHandle,'dbsettime');
pointer(dberrhandle) := GetProcedureAddress(DBLibLibraryHandle,'dberrhandle');
pointer(dbmsghandle) := GetProcedureAddress(DBLibLibraryHandle,'dbmsghandle');
pointer(dbsetopt) := GetProcedureAddress(DBLibLibraryHandle,'dbsetopt');
pointer(dbuse) := GetProcedureAddress(DBLibLibraryHandle,'dbuse');
pointer(dbcmd) := GetProcedureAddress(DBLibLibraryHandle,'dbcmd');
pointer(dbcmdrow) := GetProcedureAddress(DBLibLibraryHandle,'dbcmdrow');
pointer(dbsqlexec) := GetProcedureAddress(DBLibLibraryHandle,'dbsqlexec');
pointer(dbresults) := GetProcedureAddress(DBLibLibraryHandle,'dbresults');
pointer(dbmorecmds) := GetProcedureAddress(DBLibLibraryHandle,'dbmorecmds');
pointer(dbnextrow) := GetProcedureAddress(DBLibLibraryHandle,'dbnextrow');
pointer(dbnumcols) := GetProcedureAddress(DBLibLibraryHandle,'dbnumcols');
pointer(dbcolname) := GetProcedureAddress(DBLibLibraryHandle,'dbcolname');
pointer(dbcoltype) := GetProcedureAddress(DBLibLibraryHandle,'dbcoltype');
pointer(dbcollen) := GetProcedureAddress(DBLibLibraryHandle,'dbcollen');
pointer(dbcolinfo) := GetProcedureAddress(DBLibLibraryHandle,'dbcolinfo');
pointer(dbprtype) := GetProcedureAddress(DBLibLibraryHandle,'dbprtype');
pointer(dbdatlen) := GetProcedureAddress(DBLibLibraryHandle,'dbdatlen');
pointer(dbdata) := GetProcedureAddress(DBLibLibraryHandle,'dbdata');
pointer(dbconvert) := GetProcedureAddress(DBLibLibraryHandle,'dbconvert');
pointer(dbdatecrack) := GetProcedureAddress(DBLibLibraryHandle,'dbdatecrack');
pointer(dbcount) := GetProcedureAddress(DBLibLibraryHandle,'dbcount');
pointer(dbiscount) := GetProcedureAddress(DBLibLibraryHandle,'dbiscount');
pointer(dbcancel) := GetProcedureAddress(DBLibLibraryHandle,'dbcancel');
pointer(dbcanquery) := GetProcedureAddress(DBLibLibraryHandle,'dbcanquery');
pointer(dbexit) := GetProcedureAddress(DBLibLibraryHandle,'dbexit');
pointer(dbfreelogin) := GetProcedureAddress(DBLibLibraryHandle,{$IFDEF freetds}'dbloginfree'{$ELSE}'dbfreelogin'{$ENDIF});
pointer(dbclose) := GetProcedureAddress(DBLibLibraryHandle,'dbclose');
{$IFDEF ntwdblib}
pointer(dbopen) := GetProcedureAddress(DBLibLibraryHandle,'dbopen');
pointer(dbwinexit) := GetProcedureAddress(DBLibLibraryHandle,'dbwinexit');
{$ENDIF}
{$IFDEF freetds}
pointer(tdsdbopen) := GetProcedureAddress(DBLibLibraryHandle,'tdsdbopen');
pointer(dbtablecolinfo) := GetProcedureAddress(DBLibLibraryHandle,'dbtablecolinfo');
pointer(dbtds) := GetProcedureAddress(DBLibLibraryHandle,'dbtds');
pointer(dbsetlversion) := GetProcedureAddress(DBLibLibraryHandle,'dbsetlversion');
pointer(dbservcharset) := GetProcedureAddress(DBLibLibraryHandle,'dbservcharset');
//if not assigned(dbiscount) then
// raise EInOutError.Create('Minimum supported version of FreeTDS client library is 0.91!');
{$ENDIF}
DBLibInit:=false;
end;
end;
procedure ReleaseDBLib;
begin
if RefCount > 0 then dec(RefCount);
if RefCount = 0 then
begin
dbexit;{$IFDEF WINDOWS}dbwinexit;{$ENDIF}
if UnloadLibrary(DBLibLibraryHandle) then
DBLibLibraryHandle := NilHandle
else
inc(RefCount);
end;
end;
{$ELSE}
procedure InitialiseDBLib(LibraryName : string);
begin
//no-op for static linked
end;
procedure ReleaseDBLib;
begin
//no-op for static linked
end;
{$ENDIF LOAD_DYNAMICALLY}
//functions, which are not implemented by FreeTDS:
{$IFDEF freetds}
function dbopen(login:PLOGINREC; servername:PChar):PDBPROCESS;
begin
Result:=tdsdbopen(login, servername, 1{1=MSDBLIB or 0=SYBDBLIB});
end;
function dbsetlcharset(login:PLOGINREC; charset:PChar):RETCODE;
begin
Result:=dbsetlname(login, charset, 10);
end;
function dbsetlsecure(login:PLOGINREC):RETCODE;
begin
//not implemented; see http://www.freetds.org/userguide/domains.htm
Result:=SUCCEED;
end;
procedure dbwinexit;
begin
//do nothing
end;
{$ENDIF}
//functions which are not implemented by ntwdblib:
{$IFDEF ntwdblib}
function tdsdbopen(login:PLOGINREC; servername:PChar; msdblib:INT):PDBPROCESS;
begin
Result:=dbopen(login, servername);
end;
function dbtablecolinfo(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE;
begin
Result:=dbcolinfo(dbproc, CI_REGULAR, column, 0, dbcol);
if dbcol^.VarLength {true also when column is nullable} then
case dbcol^.Typ of
SQLCHAR : dbcol^.Typ := SQLVARCHAR;
SQLBINARY: dbcol^.Typ := SQLVARBINARY;
end;
end;
function dbsetlversion(login:PLOGINREC; version:BYTE):RETCODE;
begin
Result:=dbsetlname(login, nil, version);
end;
function dbsetlcharset(login:PLOGINREC; charset:PChar):RETCODE;
begin
Result:=SUCCEED;
end;
function dbsetlsecure(login:PLOGINREC):RETCODE;
begin
Result:=dbsetlname(login, nil, DBSETSECURE);
end;
function dbtds(dbproc:PDBPROCESS):INT;
begin
Result:=0;
end;
function dbversion():PChar;
begin
Result:='DB Library version 8.00';
end;
{$ENDIF}
{
//ntwdblib uses low significant values first
//freetds uses variable length array (based on precision) see numeric.c: tds_numeric_bytes_per_prec
// and starts from high significant values first
function dbnumerictobcd(dbnum: DBNUMERIC): TBCD;
var i: integer;
intval,intbase,intdiv: int64;
bcdval,bcdbase,bcddiv, bcd1: TBCD;
begin
intval:=0;
intbase:=1;
for i:=0 to 6 do
begin
intval := intval + dbnum.val[i] * intbase;
intbase:= intbase*256;
end;
bcdval := IntegerToBCD(intval);
if dbnum.precision > 16 then
begin
bcdbase := IntegerToBCD(intbase);
for i:=7 to length(dbnum.val)-1 do
begin
BCDMultiply(bcdbase, integer(dbnum.val[i]), bcd1);
BCDAdd(bcdval, bcd1, bcdval);
BCDMultiply(bcdbase, 256, bcdbase);
end;
end;
if dbnum.scale > 18 then
begin
bcddiv:=IntegerToBCD(int64(1000000000000000000));
for i:=19 to dbnum.scale do BCDMultiply(bcddiv, 10, bcddiv);
end
else
begin
intdiv:=1;
for i:=1 to dbnum.scale do intdiv:=intdiv*10;
bcddiv:=IntegerToBCD(intdiv);
end;
BCDDivide(bcdval, bcddiv, Result);
if dbnum.sign=0 then BCDNegate(Result);
end;
}
{$IFNDEF LOAD_DYNAMICALLY}
finalization
dbexit; {$IFDEF WINDOWS}dbwinexit;{$ENDIF}
{$ENDIF}
end.

File diff suppressed because it is too large Load Diff

View File

@ -6,15 +6,15 @@
main=fcl-db
[target]
dirs_beos=interbase postgres mysql odbc oracle sqlite
dirs_linux=interbase postgres mysql odbc oracle sqlite
dirs_freebsd=interbase postgres mysql odbc oracle sqlite
dirs_darwin=interbase postgres mysql odbc oracle sqlite
dirs_beos=interbase postgres mysql odbc oracle sqlite mssql
dirs_linux=interbase postgres mysql odbc oracle sqlite mssql
dirs_freebsd=interbase postgres mysql odbc oracle sqlite mssql
dirs_darwin=interbase postgres mysql odbc oracle sqlite
dirs_iphonesim=interbase postgres mysql odbc oracle sqlite
dirs_netbsd=interbase postgres mysql odbc oracle sqlite
dirs_openbsd=interbase postgres mysql odbc oracle sqlite
dirs_win32=interbase postgres mysql odbc oracle sqlite
dirs_win64=interbase odbc mysql sqlite
dirs_netbsd=interbase postgres mysql odbc oracle sqlite mssql
dirs_openbsd=interbase postgres mysql odbc oracle sqlite mssql
dirs_win32=interbase postgres mysql odbc oracle sqlite mssql
dirs_win64=interbase odbc mysql sqlite mssql
dirs_wince=interbase postgres mysql odbc oracle sqlite
units=sqldb
rsts=sqldb

View File

@ -18,4 +18,7 @@ T.ResourceStrings:=True;
{ Interbase/Firebird }
{$i interbase/fpmake.inc}
{ MS SQL }
{$i mssql/fpmake.inc}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
#
# Makefile.fpc for SQL IBConnection
#
[package]
main=fcl-db
[target]
units=mssqlconn
[require]
packages=dblib
[compiler]
options=-S2
[install]
fpcpackage=y
[default]
fpcdir=../../../../..
[rules]
.NOTPARALLEL:

View File

@ -0,0 +1,11 @@
{ Make DB directory and all subdirectories }
{ FULLSQLDB will be defined if included from SQLDB directory alone}
{ FULLDB will be defined if included from db directory alone}
{ FULLFCL will be defined if included from main FCL directory }
Targets.ResetDefaults;
Targets.DefaultDir:='db/sqldb/mssql';
{ Drivers only for the following OSes }
Targets.DefaultOS:=[win32,openbsd,netbsd,freebsd,linux];
T:=Targets.AddUnit('mssqlconn');
T.ResourceStrings:=False;

View File

@ -0,0 +1,20 @@
{$mode objfpc}
{$H+}
program fpmake;
uses fpmkunit;
Var
T : TTarget;
begin
ChangeDir('../../..');
With Installer do
begin
{$i ../../../fclmake.inc}
{$i fpmake.inc}
EndPackage;
Run;
end;
end.

View File

@ -0,0 +1,896 @@
{
This file is part of the Free Component Library (FCL)
MS SQL Server connection using DB-Library
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
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.
The Original Code was created by (c) 2010 Ladislav Karrach (Windows)
for the Free Pascal project.
**********************************************************************
MS SQL Server Client Library is required (ntwdblib.dll)
- or -
FreeTDS (dblib.dll)
freetds.conf: (http://www.freetds.org/userguide/freetdsconf.htm)
[global]
tds version = 7.1
client charset = UTF-8
port = 1433 or instance = ... (optional)
dump file = freetds.log (optional)
text size = 2147483647 (optional)
TMSSQLConnection properties:
HostName - can be specified also as 'servername:port' or 'servername\instance'
CharSet - if you use Microsoft DB-Lib and set to 'UTF-8' then char/varchar fields will be UTF8Encoded/Decoded
if you use FreeTDS DB-Lib then you must compile with iconv support (requires libiconv2.dll) or cast char/varchar to nchar/nvarchar in SELECTs
Params - "AutoCommit=true" - if you don't want explicitly commit/rollback transactions
"TextSize=16777216 - set maximum size of text/image data returned
}
unit mssqlconn;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, sqldb, db, BufDataset,
dblib;
type
TClientCharset = (ccNone, ccUTF8, ccISO88591, ccUnknown);
{ TMSSQLConnection }
TMSSQLConnection = class(TSQLConnection)
private
FDBLogin: PLOGINREC;
FDBProc : PDBPROCESS;
Ftds : integer; // TDS protocol version
Fstatus : STATUS; // current result/rows fetch status
procedure DBExecute(const cmd: string);
function TranslateFldType(SQLDataType: integer): TFieldType;
function ClientCharset: TClientCharset;
function AutoCommit: boolean;
function IsSybase: boolean;
protected
// Overrides from TSQLConnection
function GetHandle:pointer; override;
function GetAsSQLText(Param : TParam) : string; overload; override;
// - Connect/disconnect
procedure DoInternalConnect; override;
procedure DoInternalDisconnect; override;
// - Handle (de)allocation
function AllocateCursorHandle:TSQLCursor; override;
procedure DeAllocateCursorHandle(var cursor:TSQLCursor); override;
function AllocateTransactionHandle:TSQLHandle; override;
// - Statement handling
function StrToStatementType(s : string) : TStatementType; override;
procedure PrepareStatement(cursor:TSQLCursor; ATransaction:TSQLTransaction; buf:string; AParams:TParams); override;
procedure UnPrepareStatement(cursor:TSQLCursor); override;
// - Transaction handling
function GetTransactionHandle(trans:TSQLHandle):pointer; override;
function StartDBTransaction(trans:TSQLHandle; AParams:string):boolean; override;
function Commit(trans:TSQLHandle):boolean; override;
function Rollback(trans:TSQLHandle):boolean; override;
procedure CommitRetaining(trans:TSQLHandle); override;
procedure RollbackRetaining(trans:TSQLHandle); override;
// - Statement execution
procedure Execute(cursor:TSQLCursor; ATransaction:TSQLTransaction; AParams:TParams); override;
function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
// - Result retrieving
procedure AddFieldDefs(cursor:TSQLCursor; FieldDefs:TFieldDefs); override;
function Fetch(cursor:TSQLCursor):boolean; override;
function LoadField(cursor:TSQLCursor; FieldDef:TFieldDef; buffer:pointer; out CreateBlob : boolean):boolean; override;
procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); override;
procedure FreeFldBuffers(cursor:TSQLCursor); override;
// - UpdateIndexDefs
procedure UpdateIndexDefs(IndexDefs:TIndexDefs; TableName:string); override;
// - Schema info
function GetSchemaInfoSQL(SchemaType:TSchemaType; SchemaObjectName, SchemaObjectPattern:string):string; override;
public
constructor Create(AOwner : TComponent); override;
//property TDS:integer read Ftds;
published
// Redeclare properties from TSQLConnection
property Password;
property Transaction;
property UserName;
property CharSet;
property HostName;
// Redeclare properties from TDatabase
property Connected;
property Role;
property DatabaseName;
property KeepConnection;
property LoginPrompt;
property Params;
property OnLogin;
end;
{ TSybaseConnection }
TSybaseConnection = class(TMSSQLConnection)
public
constructor Create(AOwner : TComponent); override;
end;
{ EMSSQLDatabaseError }
EMSSQLDatabaseError = class(EDatabaseError)
public
DBErrorCode : integer;
end;
{ TMSSQLConnectionDef }
TMSSQLConnectionDef = Class(TConnectionDef)
Class Function TypeName : String; override;
Class Function ConnectionClass : TSQLConnectionClass; override;
Class Function Description : String; override;
end;
{ TSybaseConnectionDef }
TSybaseConnectionDef = Class(TConnectionDef)
Class Function TypeName : String; override;
Class Function ConnectionClass : TSQLConnectionClass; override;
Class Function Description : String; override;
end;
var
DBLibLibraryName: string = DBLIBDLL;
implementation
uses DBConst, StrUtils, FmtBCD;
type
{ TDBLibCursor }
TDBLibCursor = class(TSQLCursor)
protected
FQuery: string; //:ParamNames converted to $1,$2,..,$n
FCanOpen: boolean; //can return rows?
FRowsAffected: integer;
FParamReplaceString: string;
function ReplaceParams(AParams: TParams; ASQLConnection: TMSSQLConnection): string; //replaces parameters placeholders $1,$2,..$n in FQuery with supplied values in AParams
end;
const
SBeginTransaction = 'BEGIN TRANSACTION';
SAutoCommit = 'AUTOCOMMIT';
STextSize = 'TEXTSIZE';
var
DBErrorStr, DBMsgStr: string;
DBErrorNo, DBMsgNo: integer;
function DBErrHandler(dbproc: PDBPROCESS; severity, dberr, oserr:INT; dberrstr, oserrstr:PChar):INT; cdecl;
begin
DBErrorStr:=DBErrorStr+#13+dberrstr;
DBErrorNo :=dberr;
Result :=INT_CANCEL;
end;
function DBMsgHandler(dbproc: PDBPROCESS; msgno: DBINT; msgstate, severity:INT; msgtext, srvname, procname:PChar; line:DBUSMALLINT):INT; cdecl;
begin
DBMsgStr:=DBMsgStr+#13+msgtext;
DBMsgNo :=msgno;
Result :=0;
end;
function CheckError(const Ret: RETCODE): RETCODE;
var E: EMSSQLDatabaseError;
begin
if Ret=FAIL then
begin
E:=EMSSQLDatabaseError.Create(DBErrorStr+#13+DBMsgStr);
E.DBErrorCode:=DBErrorNo;
DBErrorStr:='';
DBMsgStr:='';
raise E;
end;
Result:=Ret;
end;
{ TDBLibCursor }
function TDBLibCursor.ReplaceParams(AParams: TParams; ASQLConnection: TMSSQLConnection): string;
var i:integer;
ParamNames, ParamValues: array of string;
begin
if Assigned(AParams) and (AParams.Count > 0) then //taken from mysqlconn, pqconnection
begin
setlength(ParamNames, AParams.Count);
setlength(ParamValues, AParams.Count);
for i := 0 to AParams.Count -1 do
begin
ParamNames[AParams.Count-i-1] := format('%s%d', [FParamReplaceString, AParams[i].Index+1]);
ParamValues[AParams.Count-i-1] := ASQLConnection.GetAsSQLText(AParams[i]);
//showmessage(ParamNames[AParams.Count-i-1] + '=' + ParamValues[AParams.Count-i-1]);
end;
Result := stringsreplace(FQuery, ParamNames, ParamValues, [rfReplaceAll]);
end
else
Result := FQuery;
end;
{ TSybaseConnection }
constructor TSybaseConnection.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Ftds := DBTDS_50;
end;
{ TMSSQLConnection }
function TMSSQLConnection.IsSybase: boolean;
begin
Result := (Ftds=DBTDS_50) or (Ftds=DBTDS_42);
end;
constructor TMSSQLConnection.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FConnOptions := FConnOptions + [sqEscapeRepeat];
//FieldNameQuoteChars:=DoubleQuotes; //default
Ftds := DBTDS_UNKNOWN;
end;
function TMSSQLConnection.GetHandle: pointer;
begin
Result:=FDBProc;
end;
function TMSSQLConnection.GetAsSQLText(Param: TParam): string;
function IsBinary(const s: string): boolean;
var i: integer;
begin
for i:=1 to length(s) do if s[i] < #9 then Exit(true);
Exit(false);
end;
function StrToHex(const s: string): string;
begin
setlength(Result, 2*length(s));
BinToHex(PChar(s), PChar(Result), length(s));
end;
begin
if not Param.IsNull then
case Param.DataType of
ftBoolean:
if Param.AsBoolean then
Result:='1'
else
Result:='0';
ftString, ftFixedChar, ftMemo:
//if IsBinary(Param.AsString) then
// Result := '0x' + StrToHex(Param.AsString)
//else
begin
Result := QuotedStr(Param.AsString);
if (Ftds >= DBTDS_70) then
Result := 'N' + Result
else if (Ftds = 0) and (ClientCharset = ccUTF8) then //hack: Microsoft DB-Lib used
Result := UTF8Decode(Result);
end;
ftBlob, ftBytes, ftVarBytes:
Result := '0x' + StrToHex(Param.AsString);
else
Result := inherited GetAsSQLText(Param);
end
else
Result:=inherited GetAsSQLText(Param);
end;
procedure TMSSQLConnection.DoInternalConnect;
const
DBVERSION: array[boolean] of BYTE = (DBVER60, DBVERSION_100);
IMPLICIT_TRANSACTIONS_OFF: array[boolean] of shortstring = ('SET IMPLICIT_TRANSACTIONS OFF', 'SET CHAINED OFF');
ANSI_DEFAULTS_ON: array[boolean] of shortstring = ('SET ANSI_DEFAULTS ON', 'SET QUOTED_IDENTIFIER ON');
CURSOR_CLOSE_ON_COMMIT_OFF: array[boolean] of shortstring = ('SET CURSOR_CLOSE_ON_COMMIT OFF', 'SET CLOSE ON ENDTRAN OFF');
begin
inherited DoInternalConnect;
InitialiseDBLib(DBLibLibraryName);
if not DBLibInit then
begin
dbinit();
dberrhandle(@DBErrHandler);
dbmsghandle(@DBMsgHandler);
DBLibInit:=true;
end;
FDBLogin:=dblogin();
if FDBLogin=nil then DatabaseError('dblogin() failed!');
// DBVERSION_100 is ATM not implemented by FreeTDS 0.91;
// set environment variable TDSVER to 5.0: Windows: SET TDSVER=5.0, Unix/Linux: TDSVER=5.0
// or in freetds.conf: include "tds version=5.0"
dbsetlversion(FDBLogin, DBVERSION[IsSybase]);
if UserName = '' then
dbsetlsecure(FDBLogin)
else
begin
dbsetlname(FDBLogin, PChar(UserName), DBSETUSER);
dbsetlname(FDBLogin, PChar(Password), DBSETPWD);
end;
if CharSet = '' then
dbsetlcharset(FDBLogin, 'UTF-8')
else
dbsetlcharset(FDBLogin, PChar(CharSet));
//dbsetlname(FDBLogin, PChar(TIMEOUT_IGNORE), DBSET_LOGINTIME);
dbsetlogintime(10);
FDBProc := dbopen(FDBLogin, PChar(HostName));
if FDBProc=nil then CheckError(FAIL);
Ftds := dbtds(FDBProc);
//CheckError( dbsetopt(FDBProc, DBQUOTEDIDENT, '') ); //in FreeTDS executes: "SET QUOTED_IDENTIFIER ON"
//CheckError( dbsetopt(FDBProc, DBTEXTSIZE, '2147483647') ); //in FreeTDS: unimplemented, returns FAIL
//CheckError( dbsetopt(FDBProc, DBTEXTLIMIT, '2147483647') ); //in FreeTDS: unimplemented, returns FAIL, but required by ntwdblib.dll
//CheckError( dbsqlexec(FDBProc) ); //after setting DBTEXTSIZE option
//CheckError (dbresults(FDBProc));
//while dbresults(FDBProc) = SUCCEED do ;
// Also SQL Server ODBC driver and Microsoft OLE DB Provider for SQL Server set ANSI_DEFAULTS to ON when connecting
//DBExecute(ANSI_DEFAULTS_ON[IsSybase]);
DBExecute('SET QUOTED_IDENTIFIER ON');
if Params.IndexOfName(STextSize) <> -1 then
DBExecute('SET TEXTSIZE '+Params.Values[STextSize])
else
DBExecute('SET TEXTSIZE 16777216');
if AutoCommit then DBExecute(IMPLICIT_TRANSACTIONS_OFF[IsSybase]); //set connection to autocommit mode - default
CheckError( dbuse(FDBProc, PChar(DatabaseName)) );
end;
procedure TMSSQLConnection.DoInternalDisconnect;
begin
inherited DoInternalDisconnect;
dbclose(FDBProc);
dbfreelogin(FDBLogin);
ReleaseDBLib;
end;
function TMSSQLConnection.AllocateCursorHandle: TSQLCursor;
begin
Result:=TDBLibCursor.Create;
end;
procedure TMSSQLConnection.DeAllocateCursorHandle(var cursor: TSQLCursor);
begin
FreeAndNil(cursor);
end;
function TMSSQLConnection.StrToStatementType(s: string): TStatementType;
begin
if s = 'EXEC' then
Result:=stExecProcedure
else
Result:=inherited StrToStatementType(s);
end;
procedure TMSSQLConnection.PrepareStatement(cursor: TSQLCursor;
ATransaction: TSQLTransaction; buf: string; AParams: TParams);
var
ParamBinding : TParamBinding;
begin
with cursor as TDBLibCursor do
begin
if assigned(AParams) and (AParams.Count > 0) then
FQuery:=AParams.ParseSQL(buf, false, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions, psSimulated, ParamBinding, FParamReplaceString)
else
FQuery:=buf;
end;
end;
procedure TMSSQLConnection.UnPrepareStatement(cursor: TSQLCursor);
begin
if assigned(FDBProc) and (Fstatus <> NO_MORE_ROWS) then
dbcanquery(FDBProc);
end;
function TMSSQLConnection.AllocateTransactionHandle: TSQLHandle;
begin
Result:=nil;
end;
function TMSSQLConnection.GetTransactionHandle(trans: TSQLHandle): pointer;
begin
Result:=nil;
end;
function TMSSQLConnection.StartDBTransaction(trans: TSQLHandle; AParams: string): boolean;
begin
Result := not AutoCommit;
if Result then
DBExecute(SBeginTransaction);
end;
function TMSSQLConnection.Commit(trans: TSQLHandle): boolean;
begin
DBExecute('COMMIT');
Result:=true;
end;
function TMSSQLConnection.Rollback(trans: TSQLHandle): boolean;
begin
DBExecute('ROLLBACK');
Result:=true;
end;
procedure TMSSQLConnection.CommitRetaining(trans: TSQLHandle);
begin
if Commit(trans) then
DBExecute(SBeginTransaction);
end;
procedure TMSSQLConnection.RollbackRetaining(trans: TSQLHandle);
begin
if Rollback(trans) then
DBExecute(SBeginTransaction);
end;
function TMSSQLConnection.AutoCommit: boolean;
begin
Result := StrToBoolDef(Params.Values[SAutoCommit], False);
end;
procedure TMSSQLConnection.DBExecute(const cmd: string);
begin
DBErrorStr:='';
DBMsgStr :='';
CheckError( dbcmd(FDBProc, PChar(cmd)) );
CheckError( dbsqlexec(FDBProc) );
CheckError( dbresults(FDBProc) );
end;
function TMSSQLConnection.ClientCharset: TClientCharset;
begin
{$IF (FPC_VERSION>=2) AND (FPC_RELEASE>4)}
case CharSet of
'' : Result := ccNone;
'UTF-8' : Result := ccUTF8;
'ISO-8859-1' : Result := ccISO88591;
else Result := ccUnknown;
end;
{$ELSE}
if CharSet = '' then
Result := ccNone
else if CharSet = 'UTF-8' then
Result := ccUTF8
else if CharSet = 'ISO-8859-1' then
Result := ccISO88591
else
Result := ccUnknown;
{$ENDIF}
end;
procedure TMSSQLConnection.Execute(cursor: TSQLCursor; ATransaction: TSQLTransaction; AParams: TParams);
var c: TDBLibCursor;
cmd: string;
res: RETCODE;
begin
c:=cursor as TDBLibCursor;
cmd := c.ReplaceParams(AParams, Self);
DBExecute(cmd);
res := SUCCEED;
repeat
c.FCanOpen := dbcmdrow(FDBProc)=SUCCEED;
c.FRowsAffected := dbcount(FDBProc);
if assigned(dbiscount) and not dbiscount(FDBProc) then
c.FRowsAffected := -1;
if not c.FCanOpen then //Sybase stored proc.
begin
repeat until dbnextrow(FDBProc) = NO_MORE_ROWS;
res := CheckError( dbresults(FDBProc) );
end;
until (res = NO_MORE_RESULTS) or c.FCanOpen;
if res = NO_MORE_RESULTS then
Fstatus := NO_MORE_ROWS
else
Fstatus := MORE_ROWS;
end;
function TMSSQLConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
begin
if assigned(cursor) then
Result := (cursor as TDBLibCursor).FRowsAffected
else
Result := inherited RowsAffected(cursor);
end;
function TMSSQLConnection.TranslateFldType(SQLDataType: integer): TFieldType;
begin
case SQLDataType of
SQLCHAR: Result:=ftFixedChar;
SQLVARCHAR: Result:=ftString;
SQLINT1, SQLINT2: Result:=ftSmallInt;
SQLINT4, SQLINTN: Result:=ftInteger;
SYBINT8: Result:=ftLargeInt;
SQLFLT4, SQLFLT8,
SQLFLTN: Result:=ftFloat;
SQLMONEY4, SQLMONEY,
SQLMONEYN: Result:=ftCurrency;
SQLDATETIM4, SQLDATETIME,
SQLDATETIMN: Result:=ftDateTime;
SQLIMAGE: Result:=ftBlob;
SQLTEXT: Result:=ftMemo;
SQLDECIMAL, SQLNUMERIC: Result:=ftBCD;
SQLBIT: Result:=ftBoolean;
SQLBINARY: Result:=ftBytes;
SQLVARBINARY: Result:=ftVarBytes;
SYBUNIQUE: Result:=ftGuid;
else
DatabaseErrorFmt('Unsupported SQL DataType %d "%s"', [SQLDataType, dbprtype(SQLDataType)]);
Result:=ftUnknown;
end;
end;
procedure TMSSQLConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TFieldDefs);
var i, FieldSize: integer;
FieldName: string;
FieldType: TFieldType;
col: DBCOL;
begin
col.SizeOfStruct:=sizeof(col);
for i:=1 to dbnumcols(FDBProc) do
begin
if dbtablecolinfo(FDBProc, i, @col) = FAIL then continue;
FieldName := col.Name;
FieldType := TranslateFldType(col.Typ);
case FieldType of
ftString, ftFixedChar:
begin
FieldSize := col.MaxLength;
if FieldSize > dsMaxStringSize then FieldSize := dsMaxStringSize;
end;
ftMemo, ftBlob,
ftBytes, ftVarBytes:
FieldSize := col.MaxLength;
ftBCD:
begin
FieldSize := col.Scale;
if (FieldSize > MaxBCDScale) or (col.Precision-col.Scale > MaxBCDPrecision-MaxBCDScale) then
FieldType := ftFmtBCD;
end;
ftGuid:
FieldSize := 38;
else
FieldSize := 0;
if col.Identity and (FieldType = ftInteger) then
FieldType := ftAutoInc;
end;
{ // dbcolinfo(), dbcoltype() maps VARCHAR->CHAR, VARBINARY->BINARY:
if col.VarLength {true also when column is nullable} then
case FieldType of
ftFixedChar: FieldType := ftString;
ftBytes : FieldType := ftVarBytes;
end;
}
with TFieldDef.Create(FieldDefs, FieldDefs.MakeNameUnique(FieldName), FieldType, FieldSize, (col.Null=0) and (not col.Identity), i) do
begin
//if col.Updatable = 0 then Attributes := Attributes + [faReadonly];
case FieldType of
ftBCD,
ftFmtBCD: Precision := col.Precision;
end;
end;
end;
end;
function TMSSQLConnection.Fetch(cursor: TSQLCursor): boolean;
begin
//Compute rows resulting from the COMPUTE clause are not processed
repeat
Fstatus := dbnextrow(FDBProc);
Result := Fstatus=REG_ROW;
until Result or (Fstatus = NO_MORE_ROWS);
if Fstatus = NO_MORE_ROWS then
while dbresults(FDBProc) <> NO_MORE_RESULTS do //process remaining results if there are any
repeat until dbnextrow(FDBProc) = NO_MORE_ROWS;
end;
function TMSSQLConnection.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef;
buffer: pointer; out CreateBlob: boolean): boolean;
var i: integer;
data, dest: PByte;
datalen, destlen: DBINT;
srctype, desttype: INT;
dbdt: DBDATETIME;
dbdr: DBDATEREC;
bcdstr: array[0..MaxFmtBCDFractionSize+2] of char;
f: double;
begin
CreateBlob:=false;
i:=FieldDef.FieldNo;
srctype:=dbcoltype(FDBProc,i);
data:=dbdata(FDBProc,i);
datalen:=dbdatlen(FDBProc,i);
Result:=assigned(data) and (datalen<>0);
if not Result then
Exit;
dest:=buffer;
destlen:=FieldDef.Size;
case FieldDef.DataType of
ftString, ftFixedChar:
desttype:=SQLCHAR;
ftBytes:
desttype:=SQLBINARY;
ftVarBytes:
begin
PWord(dest)^:=datalen;
inc(dest, sizeof(Word));
desttype:=SQLBINARY;
end;
ftSmallInt:
begin
desttype:=SQLINT2;
destlen:=sizeof(DBSMALLINT); //smallint
end;
ftAutoInc,
ftInteger:
begin
desttype:=SQLINT4;
destlen:=sizeof(DBINT); //integer
end;
ftLargeInt:
begin
desttype:=SYBINT8;
destlen:=sizeof(int64);
end;
ftCurrency,
ftFloat:
begin
desttype:=SQLFLT8;
destlen:=sizeof(DBFLT8); //double
end;
ftDateTime:
begin
dest:=@dbdt;
desttype:=SQLDATETIME;
destlen:=sizeof(dbdt);
end;
ftBCD:
begin
dest:=@f;
desttype:=SQLFLT8;
destlen:=sizeof(DBFLT8); //double
end;
ftFmtBCD:
begin
{
dbnum.precision:=FieldDef.Precision;
dbnum.scale :=FieldDef.Size;
dest:=@dbnum;
desttype:=SQLNUMERIC;
destlen:=sizeof(dbnum);
}
dest:=@bcdstr[0];
desttype:=SQLCHAR;
destlen:=sizeof(bcdstr);
fillchar(bcdstr, destlen, 0); //required when used ntwdblib.dll
end;
ftBoolean:
begin
desttype:=SQLBIT;
destlen:=sizeof(WordBool);
end;
ftGuid:
begin
desttype:=SQLCHAR;
end;
ftMemo,
ftBlob:
begin
CreateBlob:=true;
Exit;
end
else
//DatabaseErrorFmt('Tried to load field of unsupported field type %s',[FieldTypeNames[FieldDef.DataType]]);
Result:=false;
end;
dbconvert(FDBProc, srctype, data , datalen, desttype, dest, destlen);
case FieldDef.DataType of
ftString, ftFixedChar:
begin
PChar(dest + datalen)^ := #0; //strings must be null-terminated
if ((Ftds = 0) and (ClientCharset = ccUTF8)) {hack: MS DB-Lib used} or
(ClientCharset = ccISO88591) {hack: FreeTDS} then
StrPLCopy(PChar(dest), UTF8Encode(PChar(dest)), destlen);
end;
ftDateTime:
begin
//detect DBDATEREC version by pre-setting dbdr
dbdr.millisecond := -1;
if dbdatecrack(FDBProc, @dbdr, @dbdt) = SUCCEED then
begin
if dbdr.millisecond = -1 then
PDateTime(buffer)^ := composedatetime(
encodedate(dbdr.oldyear, dbdr.oldmonth, dbdr.oldday),
encodetime(dbdr.oldhour, dbdr.oldminute, dbdr.oldsecond, dbdr.oldmillisecond))
else
PDateTime(buffer)^ := composedatetime(
encodedate(dbdr.year, dbdr.month, dbdr.day),
encodetime(dbdr.hour, dbdr.minute, dbdr.second, dbdr.millisecond));
end;
end;
ftBCD:
PCurrency(buffer)^:=FloatToCurr(f);
ftFmtBCD:
PBCD(buffer)^:=StrToBCD(bcdstr, FSQLFormatSettings); //PBCD(buffer)^:=dbnumerictobcd(dbnum);
end;
end;
procedure TMSSQLConnection.LoadBlobIntoBuffer(FieldDef: TFieldDef;
ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
var data: PByte;
datalen: DBINT;
srctype: INT;
begin
//see also LoadField
srctype:=dbcoltype(FDBProc, FieldDef.FieldNo);
data:=dbdata(FDBProc, FieldDef.FieldNo);
datalen:=dbdatlen(FDBProc, FieldDef.FieldNo);
ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, datalen);
ABlobBuf^.BlobBuffer^.Size :=
dbconvert(FDBProc, srctype, data , datalen, srctype, ABlobBuf^.BlobBuffer^.Buffer, datalen);
end;
procedure TMSSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
begin
inherited FreeFldBuffers(cursor);
end;
procedure TMSSQLConnection.UpdateIndexDefs(IndexDefs: TIndexDefs; TableName: string);
const INDEXES_QUERY: array[boolean] of string=(
//MS SQL Server; TODO: we can use "execute dbo.sp_helpindex 'TableName'" when Open on Execute will fully work
'select i.name, i.indid, c.name as col_name,'+
'indexproperty(i.id, i.name, ''IsUnique''),'+
'objectproperty(o.id, ''IsPrimaryKey'') '+
'from sysindexes i '+
' join sysindexkeys k on i.id=k.id and i.indid=k.indid '+
' join syscolumns c on k.id=c.id and k.colid=c.colid '+
' left join sysobjects o on i.name=o.name and i.id=o.parent_obj '+
'where i.id=object_id(''%s'') '+
'order by k.indid, k.keyno'
,
//Sybase; http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.help.ase.15.7/title.htm
'select i.name, i.indid,' +
'index_col(object_name(i.id),i.indid,c.colid) as col_name,' +
'(i.status & 2)/2 as IsUnique,' +
'(i.status & 2048)/2048 as IsPrimaryKey ' +
'from sysindexes i '+
' join syscolumns c on c.id=i.id and c.colid<=i.keycnt-case i.indid when 1 then 0 else 1 end ' +
'where i.id=object_id(''%s'') '+
' and i.indid between 1 and 254 '+ // indid 0 is the table name, 255 is TEXT,IMAGE
'order by i.indid, c.colid'
);
var qry : TSQLQuery;
begin
//if not assigned(Transaction) then
// DatabaseError(SErrConnTransactionnSet);
qry := TSQLQuery.Create(nil);
qry.Transaction := Transaction;
qry.Database := Self;
with qry do
begin
ReadOnly := True;
SQL.Text := format(INDEXES_QUERY[IsSybase], [TableName]);
Open;
end;
while not qry.Eof do with IndexDefs.AddIndexDef do
begin
Name := trim(qry.Fields[0].AsString);
Fields := trim(qry.Fields[2].AsString);
if qry.Fields[3].AsInteger=1 then Options := Options + [ixUnique];
if qry.Fields[4].AsInteger=1 then Options := Options + [ixPrimary];
qry.Next;
while (Name = trim(qry.Fields[0].AsString)) and (not qry.Eof) do
begin
Fields := Fields + ';' + trim(qry.Fields[2].AsString);
qry.Next;
end;
end;
qry.Close;
qry.Free;
end;
function TMSSQLConnection.GetSchemaInfoSQL(SchemaType: TSchemaType; SchemaObjectName, SchemaObjectPattern: string): string;
const SCHEMA_QUERY='select name as %s from sysobjects where type=''%s'' order by 1';
begin
case SchemaType of
stTables : Result := format(SCHEMA_QUERY, ['table_name','U']);
stSysTables : Result := format(SCHEMA_QUERY, ['table_name','S']);
stProcedures : Result := format(SCHEMA_QUERY, ['proc_name','P']);
stColumns : Result := 'select name as column_name from syscolumns where id=object_id(''' + SchemaObjectName + ''') order by colorder';
else
DatabaseError(SMetadataUnavailable)
end;
end;
{ TMSSQLConnectionDef }
class function TMSSQLConnectionDef.TypeName: String;
begin
Result:='MSSQLServer';
end;
class function TMSSQLConnectionDef.ConnectionClass: TSQLConnectionClass;
begin
Result:=TMSSQLConnection;
end;
class function TMSSQLConnectionDef.Description: String;
begin
Result:='Connect to MS SQL Server via Microsoft client library or via FreeTDS db-lib';
end;
{ TSybaseConnectionDef }
class function TSybaseConnectionDef.TypeName: String;
begin
Result:='Sybase';
end;
class function TSybaseConnectionDef.ConnectionClass: TSQLConnectionClass;
begin
Result:=TSybaseConnection;
end;
class function TSybaseConnectionDef.Description: String;
begin
Result:='Connect to Sybase SQL Server via FreeTDS db-lib';;
end;
initialization
RegisterConnection(TMSSQLConnectionDef);
RegisterConnection(TSybaseConnectionDef);
finalization
UnRegisterConnection(TMSSQLConnectionDef);
UnRegisterConnection(TSybaseConnectionDef);
end.

View File

@ -0,0 +1,54 @@
Compiling FreeTDS DB-Lib with MS Visual C++ 2005/2008/2010:
===========================================================
1. Download sources from www.freetds.org
2. Open FreeTDS.dsw from /win32/msvc6 source directory
2.1 in libTDS / Header Files edit config.h and comment "HAVE_INTTYPES_H":
/* #undef HAVE_INTTYPES_H */
(http://www.freetds.org/userguide/osissues.htm#WINDOWS)
2.2 In Build / Configuration Manager select "Release"
Right-click on project "dblib_dll" and select "Properties". Note: select Configuration Properties first if in Visual C++ 2010.
C/C++ / Preprocesor / Preprocessor Definitions add "MSDBLIB" (optionally default TDS version "TDS71")
Linker / Input / Additional Dependencies add ".\tds_Release\libTDS.lib"
Linker / General / Output File change from ".\dbdll_Release\dblib_dll.dll" to ".\dbdll_Release\dblib.dll"
3. Build "dblib_dll"
4. The dblib.dll will appear in the .\dbdll_Release\ subdirectory
Note: To avoid dependency on msvc*.dll you can set in C/C++ / Code Generation / Runtime Library : "Multi-threaded (/MT)" in all projects
Compiling FreeTDS with iconv support:
=====================================
(not required when you don't use char/varchar/text datatypes or if you use character set (SBCS) ISO-8859-1 (Latin1) for your char/varchar/text columns)
1. Download libiconv developer files and binaries for Windows from http://gnuwin32.sourceforge.net/packages/libiconv.htm
Setup program: http://gnuwin32.sourceforge.net/downlinks/libiconv.php
- or -
Developer files: http://gnuwin32.sourceforge.net/downlinks/libiconv-lib-zip.php (include/iconv.h and lib/libiconv.lib)
Binaries: http://gnuwin32.sourceforge.net/downlinks/libiconv-bin-zip.php (bin/libiconv2.dll)
and extract them to a directory, e.g. the directory iconv below your root FreeTDS folder
2. in libTDS / Header Files edit config.h and uncomment /* #undef HAVE_ICONV */:
#define HAVE_ICONV 1
3. in Project properties:
libTDS: C/C++ / General / Additional Include Directories add path to "include/iconv.h" (e.g. "..\..\iconv\src\libiconv\1.9.2\libiconv-1.9.2\include"
dblib_dll: Linker / Input / Additional Dependencies add "lib/libiconv.lib" (e.g. "..\..\iconv\lib\libiconv.lib"
4. Follow regular compilation instructions above
5. Distribute libiconv2.dll with your dblib.dll
Using in Lazarus:
=================
1. Put on the form TSQLConnector and set property ConnectorType=MSSQLServer
2. Put into uses clause mssqlconn unit
Known problems:
===============
- CHAR/VARCHAR data truncated to column length when encoding to UTF-8 (use NCHAR/NVARCHAR instead or CAST char/varchar to nchar/nvarchar)
- Multiple result sets (for example when SP returns more than 1 result set only 1st is processed)
- DB-Library error 10038 "Results Pending" - set TSQLQuery.PacketRecords=-1 to fetch all pendings rows
- BLOB data (IMAGE/TEXT columns) larger than 16MB are truncated to 16MB - (set TMSSQLConnection.Params: 'TEXTSIZE=2147483647' or execute 'SET TEXTSIZE 2147483647')
(create temporary stored procedures for prepared statements)
Manuals for DB-Library API:
===========================
http://msdn.microsoft.com/en-us/library/aa936988(v=sql.80).aspx
http://manuals.sybase.com/onlinebooks/group-cnarc/cng1110e/dblib/