|
@@ -22,12 +22,15 @@ type
|
|
TTableReservation = (trNone, trSharedLockRead, trSharedLockWrite,
|
|
TTableReservation = (trNone, trSharedLockRead, trSharedLockWrite,
|
|
trProtectedLockRead, trProtectedLockWrite);
|
|
trProtectedLockRead, trProtectedLockWrite);
|
|
|
|
|
|
- TIBCursor = Class(TSQLHandle)
|
|
|
|
|
|
+ TIBCursor = Class(TSQLCursor)
|
|
protected
|
|
protected
|
|
Status : array [0..19] of ISC_STATUS;
|
|
Status : array [0..19] of ISC_STATUS;
|
|
Statement : pointer;
|
|
Statement : pointer;
|
|
FFieldFlag : array of shortint;
|
|
FFieldFlag : array of shortint;
|
|
|
|
+ FinFieldFlag : array of shortint;
|
|
SQLDA : PXSQLDA;
|
|
SQLDA : PXSQLDA;
|
|
|
|
+ in_SQLDA : PXSQLDA;
|
|
|
|
+ ParamBinding : array of integer;
|
|
end;
|
|
end;
|
|
|
|
|
|
TIBTrans = Class(TSQLHandle)
|
|
TIBTrans = Class(TSQLHandle)
|
|
@@ -48,7 +51,7 @@ type
|
|
FDialect : integer;
|
|
FDialect : integer;
|
|
|
|
|
|
procedure SetDBDialect;
|
|
procedure SetDBDialect;
|
|
- procedure AllocSQLDA(Cursor : TIBCursor;Count : integer);
|
|
|
|
|
|
+ procedure AllocSQLDA(var aSQLDA : PXSQLDA;Count : integer);
|
|
procedure TranslateFldType(SQLType, SQLLen, SQLScale : integer; var LensSet : boolean;
|
|
procedure TranslateFldType(SQLType, SQLLen, SQLScale : integer; var LensSet : boolean;
|
|
var TrType : TFieldType; var TrLen : word);
|
|
var TrType : TFieldType; var TrLen : word);
|
|
procedure SetTPB(trans : TIBtrans);
|
|
procedure SetTPB(trans : TIBtrans);
|
|
@@ -57,21 +60,22 @@ type
|
|
procedure GetFloat(CurrBuff, Buffer : pointer; Field : TFieldDef);
|
|
procedure GetFloat(CurrBuff, Buffer : pointer; Field : TFieldDef);
|
|
procedure CheckError(ProcName : string; Status : array of ISC_STATUS);
|
|
procedure CheckError(ProcName : string; Status : array of ISC_STATUS);
|
|
function getMaxBlobSize(blobHandle : TIsc_Blob_Handle) : longInt;
|
|
function getMaxBlobSize(blobHandle : TIsc_Blob_Handle) : longInt;
|
|
|
|
+ procedure SetParameters(cursor : TSQLCursor;AParams : TParams);
|
|
protected
|
|
protected
|
|
procedure DoInternalConnect; override;
|
|
procedure DoInternalConnect; override;
|
|
procedure DoInternalDisconnect; override;
|
|
procedure DoInternalDisconnect; override;
|
|
function GetHandle : pointer; override;
|
|
function GetHandle : pointer; override;
|
|
|
|
|
|
- Function AllocateCursorHandle : TSQLHandle; override;
|
|
|
|
|
|
+ Function AllocateCursorHandle : TSQLCursor; override;
|
|
Function AllocateTransactionHandle : TSQLHandle; override;
|
|
Function AllocateTransactionHandle : TSQLHandle; override;
|
|
|
|
|
|
- procedure FreeStatement(cursor : TSQLHandle); override;
|
|
|
|
- procedure PrepareStatement(cursor: TSQLHandle;ATransaction : TSQLTransaction;buf : string); override;
|
|
|
|
- procedure FreeFldBuffers(cursor : TSQLHandle); override;
|
|
|
|
- procedure Execute(cursor: TSQLHandle;atransaction:tSQLtransaction); override;
|
|
|
|
- procedure AddFieldDefs(cursor: TSQLHandle;FieldDefs : TfieldDefs); override;
|
|
|
|
- function Fetch(cursor : TSQLHandle) : boolean; override;
|
|
|
|
- function LoadField(cursor : TSQLHandle;FieldDef : TfieldDef;buffer : pointer) : boolean; override;
|
|
|
|
|
|
+ procedure CloseStatement(cursor : TSQLCursor); override;
|
|
|
|
+ procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
|
|
|
|
+ procedure FreeFldBuffers(cursor : TSQLCursor); override;
|
|
|
|
+ procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); override;
|
|
|
|
+ procedure AddFieldDefs(cursor: TSQLCursor;FieldDefs : TfieldDefs); override;
|
|
|
|
+ function Fetch(cursor : TSQLCursor) : boolean; override;
|
|
|
|
+ function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer) : boolean; override;
|
|
function GetTransactionHandle(trans : TSQLHandle): pointer; override;
|
|
function GetTransactionHandle(trans : TSQLHandle): pointer; override;
|
|
function Commit(trans : TSQLHandle) : boolean; override;
|
|
function Commit(trans : TSQLHandle) : boolean; override;
|
|
function RollBack(trans : TSQLHandle) : boolean; override;
|
|
function RollBack(trans : TSQLHandle) : boolean; override;
|
|
@@ -81,7 +85,8 @@ type
|
|
procedure UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string); override;
|
|
procedure UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string); override;
|
|
function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
|
|
function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
|
|
function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
|
|
function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
|
|
-
|
|
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner : TComponent); override;
|
|
published
|
|
published
|
|
property Dialect : integer read FDialect write FDialect;
|
|
property Dialect : integer read FDialect write FDialect;
|
|
property DatabaseName;
|
|
property DatabaseName;
|
|
@@ -93,6 +98,8 @@ type
|
|
|
|
|
|
implementation
|
|
implementation
|
|
|
|
|
|
|
|
+uses strutils;
|
|
|
|
+
|
|
resourcestring
|
|
resourcestring
|
|
SErrNoDatabaseName = 'Database connect string (DatabaseName) not filled in!';
|
|
SErrNoDatabaseName = 'Database connect string (DatabaseName) not filled in!';
|
|
|
|
|
|
@@ -165,6 +172,14 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+constructor TIBConnection.Create(AOwner : TComponent);
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ inherited;
|
|
|
|
+ FConnOptions := FConnOptions + [sqSupportParams];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
function TIBConnection.GetTransactionHandle(trans : TSQLHandle): pointer;
|
|
function TIBConnection.GetTransactionHandle(trans : TSQLHandle): pointer;
|
|
begin
|
|
begin
|
|
Result := (trans as TIBtrans).TransactionHandle;
|
|
Result := (trans as TIBtrans).TransactionHandle;
|
|
@@ -298,18 +313,15 @@ begin
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
-procedure TIBConnection.AllocSQLDA(Cursor : TIBcursor;Count : integer);
|
|
|
|
|
|
+procedure TIBConnection.AllocSQLDA(var aSQLDA : PXSQLDA;Count : integer);
|
|
|
|
|
|
begin
|
|
begin
|
|
- with cursor as TIBCursor do
|
|
|
|
- begin
|
|
|
|
- reAllocMem(SQLDA, XSQLDA_Length(Count));
|
|
|
|
|
|
+ reAllocMem(aSQLDA, XSQLDA_Length(Count));
|
|
{ Zero out the memory block to avoid problems with exceptions within the
|
|
{ Zero out the memory block to avoid problems with exceptions within the
|
|
constructor of this class. }
|
|
constructor of this class. }
|
|
- FillChar(SQLDA^, XSQLDA_Length(Count), 0);
|
|
|
|
- SQLDA^.Version := sqlda_version1;
|
|
|
|
- SQLDA^.SQLN := Count;
|
|
|
|
- end;
|
|
|
|
|
|
+ FillChar(aSQLDA^, XSQLDA_Length(Count), 0);
|
|
|
|
+ aSQLDA^.Version := sqlda_version1;
|
|
|
|
+ aSQLDA^.SQLN := Count;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TIBConnection.TranslateFldType(SQLType, SQLLen, SQLScale : integer; var LensSet : boolean;
|
|
procedure TIBConnection.TranslateFldType(SQLType, SQLLen, SQLScale : integer; var LensSet : boolean;
|
|
@@ -385,7 +397,7 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-Function TIBConnection.AllocateCursorHandle : TSQLHandle;
|
|
|
|
|
|
+Function TIBConnection.AllocateCursorHandle : TSQLCursor;
|
|
|
|
|
|
var curs : TIBCursor;
|
|
var curs : TIBCursor;
|
|
|
|
|
|
@@ -393,7 +405,8 @@ begin
|
|
curs := TIBCursor.create;
|
|
curs := TIBCursor.create;
|
|
curs.sqlda := nil;
|
|
curs.sqlda := nil;
|
|
curs.statement := nil;
|
|
curs.statement := nil;
|
|
- AllocSQLDA(curs,1);
|
|
|
|
|
|
+ AllocSQLDA(curs.SQLDA,1);
|
|
|
|
+ AllocSQLDA(curs.in_SQLDA,1);
|
|
result := curs;
|
|
result := curs;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -403,7 +416,7 @@ begin
|
|
result := TIBTrans.create;
|
|
result := TIBTrans.create;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TIBConnection.FreeStatement(cursor : TSQLHandle);
|
|
|
|
|
|
+procedure TIBConnection.CloseStatement(cursor : TSQLCursor);
|
|
begin
|
|
begin
|
|
with cursor as TIBcursor do
|
|
with cursor as TIBcursor do
|
|
begin
|
|
begin
|
|
@@ -414,28 +427,74 @@ begin
|
|
reAllocMem((cursor as tibcursor).SQLDA,0);
|
|
reAllocMem((cursor as tibcursor).SQLDA,0);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TIBConnection.PrepareStatement(cursor: TSQLHandle;ATransaction : TSQLTransaction;buf : string);
|
|
|
|
|
|
+procedure TIBConnection.PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams);
|
|
|
|
|
|
var dh : pointer;
|
|
var dh : pointer;
|
|
tr : pointer;
|
|
tr : pointer;
|
|
|
|
+ p : pchar;
|
|
x : shortint;
|
|
x : shortint;
|
|
|
|
+ i : integer;
|
|
|
|
|
|
begin
|
|
begin
|
|
|
|
+ ObtainSQLStatementType(cursor,buf);
|
|
with cursor as TIBcursor do
|
|
with cursor as TIBcursor do
|
|
begin
|
|
begin
|
|
dh := GetHandle;
|
|
dh := GetHandle;
|
|
if isc_dsql_allocate_statement(@Status, @dh, @Statement) <> 0 then
|
|
if isc_dsql_allocate_statement(@Status, @dh, @Statement) <> 0 then
|
|
CheckError('PrepareStatement', Status);
|
|
CheckError('PrepareStatement', Status);
|
|
tr := aTransaction.Handle;
|
|
tr := aTransaction.Handle;
|
|
|
|
+
|
|
|
|
+ if assigned(AParams) and (AParams.count > 0) then
|
|
|
|
+ begin
|
|
|
|
+ SetLength(ParamBinding,0);
|
|
|
|
+
|
|
|
|
+ i := posex(':',buf);
|
|
|
|
+ while i > 0 do
|
|
|
|
+ begin
|
|
|
|
+ inc(i);
|
|
|
|
+ p := @buf[i];
|
|
|
|
+ repeat
|
|
|
|
+ inc(p);
|
|
|
|
+ until (p^ in SQLDelimiterCharacters);
|
|
|
|
+
|
|
|
|
+ SetLength(ParamBinding,length(ParamBinding)+1);
|
|
|
|
+ parambinding[high(parambinding)] := AParams.ParamByName(copy(buf,i,p-@buf[i])).Index;
|
|
|
|
+
|
|
|
|
+ i := posex(':',buf,i);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ for x := 0 to AParams.count-1 do
|
|
|
|
+ buf := stringreplace(buf,':'+AParams[x].Name,'?',[rfReplaceAll,rfIgnoreCase]);
|
|
|
|
+ end;
|
|
|
|
+
|
|
if isc_dsql_prepare(@Status, @tr, @Statement, 0, @Buf[1], Dialect, nil) <> 0 then
|
|
if isc_dsql_prepare(@Status, @tr, @Statement, 0, @Buf[1], Dialect, nil) <> 0 then
|
|
CheckError('PrepareStatement', Status);
|
|
CheckError('PrepareStatement', Status);
|
|
- if StatementType = stselect then
|
|
|
|
|
|
+ if assigned(AParams) and (AParams.count > 0) then
|
|
|
|
+ begin
|
|
|
|
+ AllocSQLDA(in_SQLDA,Length(ParamBinding));
|
|
|
|
+ if isc_dsql_describe_bind(@Status, @Statement, 1, in_SQLDA) <> 0 then
|
|
|
|
+ CheckError('PrepareStatement', Status);
|
|
|
|
+ if in_SQLDA^.SQLD > in_SQLDA^.SQLN then
|
|
|
|
+ DatabaseError(SParameterCountIncorrect,self);
|
|
|
|
+ {$R-}
|
|
|
|
+ SetLength(FinFieldFlag,in_SQLDA^.SQLD);
|
|
|
|
+ for x := 0 to in_SQLDA^.SQLD - 1 do with in_SQLDA^.SQLVar[x] do
|
|
|
|
+ begin
|
|
|
|
+ if ((SQLType and not 1) = SQL_VARYING) then
|
|
|
|
+ SQLData := AllocMem(in_SQLDA^.SQLVar[x].SQLLen+2)
|
|
|
|
+ else
|
|
|
|
+ SQLData := AllocMem(in_SQLDA^.SQLVar[x].SQLLen);
|
|
|
|
+ SQLInd := @FinFieldFlag[x];
|
|
|
|
+ end;
|
|
|
|
+ {$R+}
|
|
|
|
+ end;
|
|
|
|
+ if FStatementType = stselect then
|
|
begin
|
|
begin
|
|
if isc_dsql_describe(@Status, @Statement, 1, SQLDA) <> 0 then
|
|
if isc_dsql_describe(@Status, @Statement, 1, SQLDA) <> 0 then
|
|
CheckError('PrepareSelect', Status);
|
|
CheckError('PrepareSelect', Status);
|
|
if SQLDA^.SQLD > SQLDA^.SQLN then
|
|
if SQLDA^.SQLD > SQLDA^.SQLN then
|
|
begin
|
|
begin
|
|
- AllocSQLDA((cursor as TIBCursor),SQLDA^.SQLD);
|
|
|
|
|
|
+ AllocSQLDA(SQLDA,SQLDA^.SQLD);
|
|
if isc_dsql_describe(@Status, @Statement, 1, SQLDA) <> 0 then
|
|
if isc_dsql_describe(@Status, @Statement, 1, SQLDA) <> 0 then
|
|
CheckError('PrepareSelect', Status);
|
|
CheckError('PrepareSelect', Status);
|
|
end;
|
|
end;
|
|
@@ -454,7 +513,7 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TIBConnection.FreeFldBuffers(cursor : TSQLHandle);
|
|
|
|
|
|
+procedure TIBConnection.FreeFldBuffers(cursor : TSQLCursor);
|
|
var
|
|
var
|
|
x : shortint;
|
|
x : shortint;
|
|
begin
|
|
begin
|
|
@@ -465,17 +524,18 @@ begin
|
|
{$R+}
|
|
{$R+}
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TIBConnection.Execute(cursor: TSQLHandle;atransaction:tSQLtransaction);
|
|
|
|
|
|
+procedure TIBConnection.Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams);
|
|
var tr : pointer;
|
|
var tr : pointer;
|
|
begin
|
|
begin
|
|
tr := aTransaction.Handle;
|
|
tr := aTransaction.Handle;
|
|
-
|
|
|
|
|
|
+ if Assigned(APArams) and (AParams.count > 0) then SetParameters(cursor, AParams);
|
|
with cursor as TIBCursor do
|
|
with cursor as TIBCursor do
|
|
- if isc_dsql_execute(@Status, @tr, @Statement, 1, nil) <> 0 then
|
|
|
|
|
|
+ if isc_dsql_execute2(@Status, @tr, @Statement, 1, in_SQLDA, nil) <> 0 then
|
|
CheckError('Execute', Status);
|
|
CheckError('Execute', Status);
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TIBConnection.AddFieldDefs(cursor: TSQLHandle;FieldDefs : TfieldDefs);
|
|
|
|
|
|
+
|
|
|
|
+procedure TIBConnection.AddFieldDefs(cursor: TSQLCursor;FieldDefs : TfieldDefs);
|
|
var
|
|
var
|
|
x : integer;
|
|
x : integer;
|
|
lenset : boolean;
|
|
lenset : boolean;
|
|
@@ -505,7 +565,7 @@ begin
|
|
Result := FSQLDatabaseHandle;
|
|
Result := FSQLDatabaseHandle;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TIBConnection.Fetch(cursor : TSQLHandle) : boolean;
|
|
|
|
|
|
+function TIBConnection.Fetch(cursor : TSQLCursor) : boolean;
|
|
var
|
|
var
|
|
retcode : integer;
|
|
retcode : integer;
|
|
begin
|
|
begin
|
|
@@ -518,7 +578,48 @@ begin
|
|
Result := (retcode <> 100);
|
|
Result := (retcode <> 100);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TIBConnection.LoadField(cursor : TSQLHandle;FieldDef : TfieldDef;buffer : pointer) : boolean;
|
|
|
|
|
|
+procedure TIBConnection.SetParameters(cursor : TSQLCursor;AParams : TParams);
|
|
|
|
+
|
|
|
|
+var ParNr,SQLVarNr : integer;
|
|
|
|
+ s : string;
|
|
|
|
+ i : integer;
|
|
|
|
+ currbuff : pchar;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+{$R-}
|
|
|
|
+ with cursor as TIBCursor do for SQLVarNr := 0 to High(ParamBinding){AParams.count-1} do
|
|
|
|
+ begin
|
|
|
|
+ ParNr := ParamBinding[SQLVarNr];
|
|
|
|
+ if AParams[ParNr].IsNull then
|
|
|
|
+ in_sqlda^.SQLvar[SQLVarNr].SQLInd^ := -1
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ in_sqlda^.SQLvar[SQLVarNr].SQLInd^ := 0;
|
|
|
|
+
|
|
|
|
+ case AParams[ParNr].DataType of
|
|
|
|
+ ftInteger :
|
|
|
|
+ begin
|
|
|
|
+ i := AParams[ParNr].AsInteger;
|
|
|
|
+ Move(i, in_sqlda^.SQLvar[SQLVarNr].SQLData^, in_SQLDA^.SQLVar[SQLVarNr].SQLLen);
|
|
|
|
+ end;
|
|
|
|
+ ftString :
|
|
|
|
+ begin
|
|
|
|
+ {$R-}
|
|
|
|
+ s := AParams[ParNr].AsString;
|
|
|
|
+ Move(s[1], in_sqlda^.SQLvar[SQLVarNr].SQLData^, length(s));
|
|
|
|
+ {$R+}
|
|
|
|
+ end;
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ DatabaseError('This kind of parameter in not (yet) supported.',self);
|
|
|
|
+ end;
|
|
|
|
+ end {case}
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+{$R+}
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TIBConnection.LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer) : boolean;
|
|
|
|
|
|
var
|
|
var
|
|
x : integer;
|
|
x : integer;
|