1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174 |
- { $Id$
- Copyright (c) 2000 by Pavel Stingl
- Interbase database & dataset
- 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.
- **********************************************************************}
- unit Interbase;
- {$mode objfpc}
- {$H+}
- {$M+} // ### remove this!!!
- interface
- uses SysUtils, Classes, IBase60, DB;
- type
- PInteger = ^integer;
- PSmallInt= ^smallint;
- TIBDatabase = class;
- TIBTransaction = class;
- TIBQuery = class;
- TIBStoredProc = class;
- EInterBaseError = class(Exception);
- { TIBDatabase }
- TIBDatabase = class (TDatabase)
- private
- FIBDatabaseHandle : pointer;
- FPassword : string;
- FStatus : array [0..19] of ISC_STATUS;
- FTransaction : TIBTransaction;
- FUserName : string;
- FCharSet : string;
- FDialect : integer;
- FRole : String;
-
- procedure SetDBDialect;
- procedure SetTransaction(Value : TIBTransaction);
- protected
- function GetHandle : pointer; virtual;
- { This procedure makes connection to Interbase server internally.
- Is visible only by descendants, in application programming
- will be invisible. Connection you must establish by setting
- @link(Connected) property to true, or by call of Open method.
- }
- procedure DoInternalConnect; override;
- { This procedure disconnects object from IB server internally.
- Is visible only by descendants, in application programming
- will be invisible. Disconnection you must make by setting
- @link(Connected) property to false, or by call of Close method.
- }
- procedure DoInternalDisconnect; override;
- public
- procedure StartTransaction; override;
- procedure EndTransaction; override;
- destructor Destroy; override;
- property Handle: Pointer read GetHandle;
- published
- { On connect, TIBDatabase object retrieve SQL dialect of database file,
- and sets this property to responding value }
- property Dialect : integer read FDialect write FDialect;
- { Before firing Open method you must set @link(Password),@link(DatabaseName),
- @link(UserName) properties in order of successfull connect to database }
- property Password : string read FPassword write FPassword;
- { This property holds default transaction for database. You must assign it by hand
- now, default assignment becomes handy, in next release, with transaction
- handling and evidence }
- property Transaction : TIBTransaction read FTransaction write SetTransaction;
- { Before firing Open method you must set @link(Password),@link(DatabaseName),
- @link(UserName) properties in order of successfull connect to database }
- property UserName : string read FUserName write FUserName;
- { The character set used in SQL statements }
- property CharSet : string read FCharSet write FCharSet;
- { Identifies, if connection to Interbase server is established, or not.
- Instead of calling Open, Close methods you can connect or disconnect
- by setting this property to true or false.
- }
- property Connected;
- { This property holds database connect string. On local server it will be
- absolute path to the db file, if you wanna connect over network, this
- path looks like this: <server_name>:<path_on_server>, where server_name
- is absolute IP address, or name of server in DNS or hosts file, path_on_server
- is absolute path to the file again }
- Property Role : String read FRole write FRole;
- property DatabaseName;
- property KeepConnection;
- property LoginPrompt;
- property Params;
- property OnLogin;
- end;
- { TIBTransaction }
- {
- Interbase has two modes for commit and rollback transactions,
- the difference is simple. If you execute Commit or Rollback,
- current transaction ends, and you must create new one.
- If you, on other side, need only commit or rollback data
- without transaction closing, execute with CommitRetaining or
- RollbackRetaining. Transaction handle, environment etc. will be
- as same as before action. Possible values are : caNone, caCommit, caCommitRetaining, caRollback,
- caRollbackRetaining
- }
- TCommitRollbackAction = (caNone, caCommit, caCommitRetaining, caRollback,
- caRollbackRetaining);
- TAccessMode = (amReadWrite, amReadOnly);
- TIsolationLevel = (ilConcurrent, ilConsistent, ilReadCommittedRecV,
- ilReadCommitted);
- TLockResolution = (lrWait, lrNoWait);
- TTableReservation = (trNone, trSharedLockRead, trSharedLockWrite,
- trProtectedLockRead, trProtectedLockWrite);
- TIBTransaction = class (TComponent)
- private
- FTransactionHandle : pointer; // Transaction handle
- FAction : TCommitRollbackAction;
- FActive : boolean;
- FTPB : string; // Transaction parameter buffer
- FDatabase : TIBDatabase;
- FAccessMode : TAccessMode;
- FIsolationLevel : TIsolationLevel;
- FLockResolution : TLockResolution;
- FTableReservation : TTableReservation;
- FStatus : array [0..19] of ISC_STATUS;
- procedure SetActive(Value : boolean);
- procedure SetTPB;
- protected
- function GetHandle : pointer; virtual;
- public
- { Commits all actions, which was made in transaction, and closes transaction}
- procedure Commit; virtual;
- { Commits all actions, closes transaction, and creates new one }
- procedure CommitRetaining; virtual;
- { Rollbacks all actions made in transaction, and closes transaction }
- procedure Rollback; virtual;
- { Rollbacks all actions made in transaction, closes trans. and creates new one }
- procedure RollbackRetaining; virtual;
- { Creates new transaction. If transaction is active, closes it and make new one.
- Action taken while closing responds to @link(Action) property settings }
- procedure StartTransaction;
- constructor Create(AOwner : TComponent); override;
- destructor Destroy; override;
- property Handle: Pointer read GetHandle;
- published
- { Default action while closing transaction by setting
- @link(Active) property. For details see @link(TCommitRollbackAction)}
- property Action : TCommitRollbackAction read FAction write FAction;
- { Is set to true while transaction is active, false if not.
- If you set it manually to true, object executes
- @link(StartTransaction) method, if transaction is
- active, and you set Active to false, object executes
- one of @link(Commit), @link(CommitRetaining), @link(Rollback),
- @link(RollbackRetaining) methods, depending on @link(Action) property
- setting.
- }
- property Active : boolean read FActive write SetActive;
- { Transaction must be assigned to some database session, for which purpose
- you must use this property}
- property Database : TIBDatabase read FDatabase write FDatabase;
- end;
- { TIBQuery }
- PIBBookmark = ^TIBBookmark;
- TIBBookmark = record
- BookmarkData : integer;
- BookmarkFlag : TBookmarkFlag;
- end;
- TStatementType = (stNone, stSelect, stInsert, stUpdate, stDelete,
- stDDL, stGetSegment, stPutSegment, stExecProcedure,
- stStartTrans, stCommit, stRollback, stSelectForUpd);
- TIBQuery = class (TDBDataset)
- private
- FOpen : Boolean;
- FTransaction : TIBTransaction;
- FDatabase : TIBDatabase;
- FStatus : array [0..19] of ISC_STATUS;
- FFieldFlag : array [0..1023] of shortint;
- FBufferSize : integer;
- FSQLDA : PXSQLDA;
- FSQLDAAllocated : integer;
- FStatement : pointer;
- FRecordCount : integer;
- FRecordSize : word;
- FCurrentRecord : integer;
- FSQL : TStrings;
- FPrepared : boolean;
- FIsEOF : boolean;
- FStatementType : TStatementType;
- FLoadingFieldDefs : boolean;
- procedure SetDatabase(Value : TIBDatabase);
- procedure SetTransaction(Value : TIBTransaction);
- procedure AllocSQLDA(Count : integer);
- procedure AllocStatement;
- procedure FreeStatement;
- procedure PrepareStatement;
- procedure DescribeStatement;
- procedure SetUpSQLVars;
- procedure AllocFldBuffers;
- procedure FreeFldBuffers;
- procedure Fetch;
- function LoadBufferFromSQLDA(Buffer : PChar): TGetResult;
- procedure GetStatementType;
- procedure SetFieldSizes;
- procedure TranslateFldType(SQLType, SQLLen : integer; var LensSet : boolean;
- var TrType : TFieldType; var TrLen : word);
- procedure ExecuteImmediate;
- procedure ExecuteParams;
- procedure Execute;
- // conversion methods
- procedure GetDateTime(CurrBuff, Buffer : pointer; AType : integer);
- procedure GetFloat(CurrBuff, Buffer : pointer; Field : TField);
- protected
- // abstract & virual methods of TDataset
- function AllocRecordBuffer: PChar; override;
- procedure FreeRecordBuffer(var Buffer: PChar); override;
- procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
- function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
- function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;
- function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
- function GetRecordCount: integer; override;
- function GetRecordSize: Word; override;
- procedure InternalAddRecord(Buffer: Pointer; AAppend: Boolean); override;
- procedure InternalClose; override;
- procedure InternalDelete; override;
- procedure InternalFirst; override;
- procedure InternalGotoBookmark(ABookmark: Pointer); override;
- procedure InternalHandleException; override;
- procedure InternalInitFieldDefs; override;
- procedure InternalInitRecord(Buffer: PChar); override;
- procedure InternalLast; override;
- procedure InternalOpen; override;
- procedure InternalPost; override;
- procedure InternalSetToRecord(Buffer: PChar); override;
- function IsCursorOpen: Boolean; override;
- procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
- procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;
- procedure SetFieldData(Field: TField; Buffer: Pointer); override;
- public
- { This method is used for executing sql statements, which
- doesn't return any rows. (insert,delete,update, and DDL commands) }
- procedure ExecSQL; virtual;
- constructor Create(AOwner : TComponent); override;
- destructor Destroy; override;
- published
- { Query must have transaction assigned. If transaction is not assigned, and database
- is, object looks, if database have default transaction, and assigns it }
- property Transaction : TIBTransaction read FTransaction write SetTransaction;
- { Use this property to determine, which database session can query use }
- property Database : TIBDatabase read FDatabase write SetDatabase;
- { This property holds SQL command, which you want to execute }
- property SQL : TStrings read FSQL write FSQL;
- end;
- { TIBStoredProc - not implemented - yet :-/}
- TIBStoredProc = class (TDataset)
- private
- protected
- public
- published
- end;
- implementation
- type
- TTm = packed record
- tm_sec : longint;
- tm_min : longint;
- tm_hour : longint;
- tm_mday : longint;
- tm_mon : longint;
- tm_year : longint;
- tm_wday : longint;
- tm_yday : longint;
- tm_isdst : longint;
- __tm_gmtoff : longint;
- __tm_zone : Pchar;
- end;
- procedure CheckError(ProcName : string; Status : array of ISC_STATUS);
- var
- buf : array [0..1024] of char;
- p : pointer;
- Msg : string;
- begin
- if ((Status[0] = 1) and (Status[1] <> 0)) then
- begin
- p := @Status;
- while isc_interprete(Buf, @p) > 0 do
- Msg := Msg + #10' -' + StrPas(Buf);
- raise EInterBaseError.Create(ProcName + ': ' + Msg);
- end;
- end;
- { TIBDatabase }
- procedure TIBDatabase.SetDBDialect;
- var
- x : integer;
- Len : integer;
- Buffer : string;
- ResBuf : array [0..39] of byte;
- begin
- Buffer := Chr(isc_info_db_sql_dialect) + Chr(isc_info_end);
- if isc_database_info(@FStatus, @FIBDatabaseHandle, Length(Buffer),
- @Buffer[1], SizeOf(ResBuf), @ResBuf) <> 0 then
- CheckError('TIBDatabse.SetDBDialect', FStatus);
- x := 0;
- while x < 40 do
- case ResBuf[x] of
- isc_info_db_sql_dialect :
- begin
- Inc(x);
- Len := isc_vax_integer(@ResBuf[x], 2);
- Inc(x, 2);
- FDialect := isc_vax_integer(@ResBuf[x], Len);
- Inc(x, Len);
- end;
- isc_info_end : Break;
- end;
- end;
- procedure TIBDatabase.SetTransaction(Value : TIBTransaction);
- begin
- if FTransaction = nil then
- begin
- FTransaction := Value;
- if Assigned(FTransaction) then
- FTransaction.Database := Self;
- exit;
- end;
- if (Value <> FTransaction) and (Value <> nil) then
- if (not FTransaction.Active) then
- begin
- FTransaction := Value;
- FTransaction.Database := Self;
- end
- else
- raise EInterBaseError.Create('Cannot assign transaction while old transaction active!');
- end;
- function TIBDatabase.GetHandle: pointer;
- begin
- Result := FIBDatabaseHandle;
- end;
- procedure TIBDatabase.DoInternalConnect;
- var
- DPB : string;
- begin
- if Connected then
- Close;
- DPB := chr(isc_dpb_version1);
- if (FUserName <> '') then
- begin
- DPB := DPB + chr(isc_dpb_user_name) + chr(Length(FUserName)) + FUserName;
- if (FPassword <> '') then
- DPB := DPB + chr(isc_dpb_password) + chr(Length(FPassword)) + FPassword;
- end;
- if (FRole <> '') then
- DPB := DPB + chr(isc_dpb_sql_role_name) + chr(Length(FRole)) + FRole;
- if Length(CharSet) > 0 then
- DPB := DPB + Chr(isc_dpb_lc_ctype) + Chr(Length(CharSet)) + CharSet;
- if (DatabaseName = '') then
- raise EInterBaseError.Create('TIBDatabase.Open: Database connect string not filled in!');
- FIBDatabaseHandle := nil;
- if isc_attach_database(@FStatus, Length(DatabaseName), @DatabaseName[1], @FIBDatabaseHandle,
- Length(DPB), @DPB[1]) <> 0 then
- CheckError('TIBDatabase.Open', FStatus);
- SetDBDialect;
- end;
- procedure TIBDatabase.DoInternalDisconnect;
- begin
- if not Connected then
- begin
- FIBDatabaseHandle := nil;
- Exit;
- end;
- isc_detach_database(@FStatus[0], @FIBDatabaseHandle);
- CheckError('TIBDatabase.Close', FStatus);
- end;
- procedure TIBDatabase.StartTransaction;
- begin
- if FTransaction = nil then
- raise EDatabaseError.Create('TIBDatabase.StartTransaction: Transaction not set');
- FTransaction.Active := True;
- end;
- procedure TIBDatabase.EndTransaction;
- begin
- if FTransaction = nil then
- raise EDatabaseError.Create('TIBDatabase.EndTransaction: Transaction not set');
- FTransaction.Active := False;
- end;
- destructor TIBDatabase.Destroy;
- begin
- if FTransaction <> nil then
- begin
- FTransaction.Active := False;
- FTransaction.Database := nil;
- end;
- inherited Destroy;
- end;
- { TIBTransaction }
- procedure TIBTransaction.SetActive(Value : boolean);
- begin
- if FActive and (not Value) then
- Rollback
- else if (not FActive) and Value then
- StartTransaction;
- end;
- procedure TIBTransaction.SetTPB;
- begin
- FTPB := chr(isc_tpb_version3);
- case FAccessMode of
- amReadWrite : FTPB := FTPB + chr(isc_tpb_write);
- amReadOnly : FTPB := FTPB + chr(isc_tpb_read);
- end;
- case FIsolationLevel of
- ilConsistent : FTPB := FTPB + chr(isc_tpb_consistency);
- ilConcurrent : FTPB := FTPB + chr(isc_tpb_concurrency);
- ilReadCommittedRecV : FTPB := FTPB + chr(isc_tpb_read_committed) +
- chr(isc_tpb_rec_version);
- ilReadCommitted : FTPB := FTPB + chr(isc_tpb_read_committed) +
- chr(isc_tpb_no_rec_version);
- end;
- case FLockResolution of
- lrWait : FTPB := FTPB + chr(isc_tpb_wait);
- lrNoWait : FTPB := FTPB + chr(isc_tpb_nowait);
- end;
- case FTableReservation of
- trSharedLockRead : FTPB := FTPB + chr(isc_tpb_shared) +
- chr(isc_tpb_lock_read);
- trSharedLockWrite : FTPB := FTPB + chr(isc_tpb_shared) +
- chr(isc_tpb_lock_write);
- trProtectedLockRead : FTPB := FTPB + chr(isc_tpb_protected) +
- chr(isc_tpb_lock_read);
- trProtectedLockWrite : FTPB := FTPB + chr(isc_tpb_protected) +
- chr(isc_tpb_lock_write);
- end;
- end;
- function TIBTransaction.GetHandle: pointer;
- begin
- Result := FTransactionHandle;
- end;
- procedure TIBTransaction.Commit;
- begin
- if not FActive then Exit;
- if isc_commit_transaction(@FStatus, @FTransactionHandle) <> 0 then
- CheckError('TIBTransaction.Commit', FStatus)
- else FActive := False;
- end;
- procedure TIBTransaction.CommitRetaining;
- begin
- if not FActive then Exit;
- if isc_commit_retaining(@FStatus, @FTransactionHandle) <> 0 then
- CheckError('TIBTransaction.CommitRetaining', FStatus);
- end;
- procedure TIBTransaction.Rollback;
- begin
- if not FActive then Exit;
- if isc_rollback_transaction(@FStatus, @FTransactionHandle) <> 0 then
- CheckError('TIBTransaction.Rollback', FStatus)
- else FActive := False;
- end;
- procedure TIBTransaction.RollbackRetaining;
- begin
- if not FActive then Exit;
- if isc_rollback_retaining(@FStatus, @FTransactionHandle) <> 0 then
- CheckError('TIBTransaction.RollbackRetaining', FStatus);
- end;
- procedure TIBTransaction.StartTransaction;
- var
- DBHandle : pointer;
- begin
- if Active then Active := False;
- if FDatabase = nil then
- raise EInterBaseError.Create('TIBTransaction.StartTransaction: Database not assigned!');
- if not Database.Connected then
- Database.Open;
- DBHandle := Database.GetHandle;
- SetTPB;
- FTransactionHandle := nil;
- if isc_start_transaction(@FStatus, @FTransactionHandle, 1,
- [@DBHandle, Length(FTPB), @FTPB[1]]) <> 0 then
- CheckError('TIBTransaction.StartTransaction',FStatus)
- else FActive := True;
- end;
- constructor TIBTransaction.Create(AOwner : TComponent);
- begin
- inherited Create(AOwner);
- FIsolationLevel := ilReadCommitted;
- end;
- destructor TIBTransaction.Destroy;
- begin
- // This will also do a Rollback, if the transaction is currently active
- Active := False;
- if Database <> nil then
- Database.Transaction := nil;
- inherited Destroy;
- end;
- { TIBQuery }
- procedure TIBQuery.SetTransaction(Value : TIBTransaction);
- begin
- CheckInactive;
- if (FTransaction <> Value) then
- FTransaction := Value;
- end;
- procedure TIBQuery.SetDatabase(Value : TIBDatabase);
- begin
- CheckInactive;
- if (FDatabase <> Value) then
- begin
- FDatabase := Value;
- if (FTransaction = nil) and (Assigned(FDatabase.Transaction)) then
- SetTransaction(FDatabase.Transaction);
- end;
- end;
- procedure TIBQuery.AllocSQLDA(Count : integer);
- begin
- if FSQLDAAllocated > 0 then
- FreeMem(FSQLDA);
- GetMem(FSQLDA, XSQLDA_Length(Count));
- { Zero out the memory block to avoid problems with exceptions within the
- constructor of this class. }
- FillChar(FSQLDA^, XSQLDA_Length(Count), 0);
- FSQLDAAllocated := Count;
- FSQLDA^.Version := sqlda_version1;
- FSQLDA^.SQLN := Count;
- end;
- procedure TIBQuery.AllocStatement;
- var
- dh : pointer;
- begin
- if not FDatabase.Connected then
- FDatabase.Open;
- dh := FDatabase.GetHandle;
- if isc_dsql_allocate_statement(@FStatus, @dh, @FStatement) <> 0 then
- CheckError('TIBQuery.AllocStatement', FStatus);
- end;
- procedure TIBQuery.FreeStatement;
- begin
- if isc_dsql_free_statement(@FStatus, @FStatement, DSQL_Drop) <> 0 then
- CheckError('TIBQuery.FreeStatement', FStatus);
- FStatement := nil;
- end;
- procedure TIBQuery.PrepareStatement;
- var
- Buf : string;
- x : integer;
- tr : pointer;
- begin
- tr := FTransaction.GetHandle;
- for x := 0 to FSQL.Count - 1 do
- Buf := Buf + FSQL[x] + ' ';
- if isc_dsql_prepare(@FStatus, @tr, @FStatement, 0, @Buf[1], Database.Dialect, nil) <> 0 then
- CheckError('TIBQuery.PrepareStatement', FStatus);
- end;
- procedure TIBQuery.DescribeStatement;
- begin
- if isc_dsql_describe(@FStatus, @FStatement, 1, FSQLDA) <> 0 then
- CheckError('TIBQuery.DescribeStatement', FStatus);
- if FSQLDA^.SQLD > FSQLDA^.SQLN then
- begin
- AllocSQLDA(FSQLDA^.SQLD);
- if isc_dsql_describe(@FStatus, @FStatement, 1, FSQLDA) <> 0 then
- CheckError('TIBQuery.DescribeStatement', FStatus);
- end;
- end;
- procedure TIBQuery.SetUpSQLVars;
- var
- x : integer;
- begin
- for x := 0 to FSQLDA^.SQLN - 1 do
- begin
- case FSQLDA^.SQLVar[x].SQLType of
- sql_varying + 1:
- FSQLDA^.SQLVar[x].SQLType := sql_varying;
- sql_text + 1 :
- FSQLDA^.SQLVar[x].SQLType := sql_text;
- sql_short, sql_short + 1, sql_long + 1:
- FSQLDA^.SQLVar[x].SQLType := sql_long;
- sql_float + 1 :
- FSQLDA^.SQLVar[x].SQLType := sql_float;
- sql_double + 1 :
- FSQLDA^.SQLVar[x].SQLType := sql_double;
- sql_blob + 1 :
- FSQLDA^.SQLVar[x].SQLType := sql_blob;
- sql_type_time + 1 :
- FSQLDA^.SQLVar[x].SQLType := sql_type_time;
- sql_timestamp + 1:
- FSQLDA^.SQLVar[x].SQLType := sql_timestamp;
- end;
- end;
- end;
- procedure TIBQuery.AllocFldBuffers;
- var
- x : shortint;
- begin
- {$R-}
- for x := 0 to FSQLDA^.SQLD - 1 do
- begin
- FSQLDA^.SQLVar[x].SQLData := AllocMem(FSQLDA^.SQLVar[x].SQLLen);
- FSQLDA^.SQLVar[x].SQLInd := @FFieldFlag[x];
- end;
- {$R+}
- end;
- procedure TIBQuery.FreeFldBuffers;
- var
- x : integer;
- begin
- {$R-}
- for x := 0 to FSQLDA^.SQLD - 1 do
- begin
- if FSQLDA^.SQLVar[x].SQLData <> nil then
- begin
- FreeMem(FSQLDA^.SQLVar[x].SQLData);
- FSQLDA^.SQLVar[x].SQLData := nil;
- end;
- end;
- {$R+}
- end;
- procedure TIBQuery.Fetch;
- var
- retcode : integer;
- begin
- if not (FStatementType in [stSelect]) then
- Exit;
- retcode := isc_dsql_fetch(@FStatus, @FStatement, 1, FSQLDA);
- if (retcode <> 0) and (retcode <> 100) then
- CheckError('TIBQuery.Fetch', FStatus);
- FIsEOF := (retcode = 100);
- end;
- function TIBQuery.LoadBufferFromSQLDA(Buffer : PChar): TGetResult;
- var
- x : integer;
- VarcharLen : word;
- begin
- Fetch;
- if FIsEOF then
- begin
- Result := grEOF;
- Exit;
- end;
- {$R-}
- for x := 0 to FSQLDA^.SQLD - 1 do
- begin
- with FSQLDA^.SQLVar[x] do
- begin
- if ((SQLType and not 1) = SQL_VARYING) then
- begin
- Move(SQLData^, VarcharLen, 2);
- Move((SQLData + 2)^, Buffer^, VarcharLen);
- PChar(Buffer + VarcharLen)^ := #0;
- end
- else Move(SQLData^, Buffer^, SQLLen);
- Inc(Buffer, SQLLen);
- end;
- end;
- {$R+}
- Result := grOK;
- end;
- procedure TIBQuery.GetStatementType;
- var
- x : integer;
- ResBuf : array [0..7] of char;
- begin
- FStatementType := stNone;
- x := isc_info_sql_stmt_type;
- if isc_dsql_sql_info(@FStatus, @FStatement, SizeOf(X),
- @x, SizeOf(ResBuf), @ResBuf) <> 0 then
- CheckError('TIBQuery.GetStatementType', FStatus);
- if Ord(ResBuf[0]) = isc_info_sql_stmt_type then
- begin
- x := isc_vax_integer(@ResBuf[1], 2);
- FStatementType := TStatementType(isc_vax_integer(@ResBuf[3], x));
- end;
- end;
- procedure TIBQuery.SetFieldSizes;
- var
- x : integer;
- begin
- FRecordSize := 0;
- FBufferSize := 0;
- {$R-}
- for x := 0 to FSQLDA^.SQLD - 1 do
- Inc(FRecordSize, FSQLDA^.SQLVar[x].SQLLen);
- {$R+}
- FBufferSize := FRecordSize + SizeOf(TIBBookmark);
- end;
- procedure TIBQuery.TranslateFldType(SQLType, SQLLen : integer; var LensSet : boolean;
- var TrType : TFieldType; var TrLen : word);
- begin
- LensSet := False;
- case (SQLType and not 1) of
- SQL_VARYING :
- begin
- LensSet := True;
- TrType := ftString;
- TrLen := SQLLen;
- end;
- SQL_TEXT :
- begin
- LensSet := True;
- TrType := ftString;
- TrLen := SQLLen;
- end;
- SQL_TYPE_DATE :
- TrType := ftDateTime;
- SQL_TYPE_TIME :
- TrType := ftDateTime;
- SQL_TIMESTAMP :
- TrType := ftDateTime;
- SQL_ARRAY :
- begin
- end;
- SQL_BLOB :
- begin
- end;
- SQL_SHORT :
- begin
- LensSet := True;
- TrLen := SQLLen;
- TrType := ftInteger;
- end;
- SQL_LONG :
- begin
- LensSet := True;
- TrLen := SQLLen;
- TrType := ftInteger;
- end;
- SQL_INT64 :
- {TrType := ftInt64};
- SQL_DOUBLE :
- begin
- LensSet := True;
- TrLen := SQLLen;
- TrType := ftFloat;
- end;
- SQL_FLOAT :
- begin
- LensSet := True;
- TrLen := SQLLen;
- TrType := ftFloat;
- end;
- end;
- end;
- procedure TIBQuery.ExecuteImmediate;
- begin
- end;
- procedure TIBQuery.ExecuteParams;
- begin
- //!! to be implemented
- end;
- procedure TIBQuery.Execute;
- var
- tr : pointer;
- begin
- tr := FTransaction.GetHandle;
- if isc_dsql_execute(@FStatus, @tr, @FStatement, 1, nil) <> 0 then
- CheckError('TIBQuery.Execute', FStatus);
- end;
- procedure TIBQuery.GetDateTime(CurrBuff, Buffer : pointer; AType : integer);
- var
- CTime : TTm; // C struct time
- STime : TSystemTime; // System time
- PTime : TDateTime; // Pascal time
- begin
- case (AType and not 1) of
- SQL_TYPE_DATE :
- isc_decode_sql_date(PISC_DATE(CurrBuff), @CTime);
- SQL_TYPE_TIME :
- isc_decode_sql_time(PISC_TIME(CurrBuff), @CTime);
- SQL_TIMESTAMP :
- isc_decode_timestamp(PISC_TIMESTAMP(CurrBuff), @CTime);
- end;
- STime.Year := CTime.tm_year + 1900;
- STime.Month := CTime.tm_mon + 1;
- STime.Day := CTime.tm_mday;
- STime.Hour := CTime.tm_hour;
- STime.Minute := CTime.tm_min;
- STime.Second := CTime.tm_sec;
- STime.Millisecond := 0;
- PTime := SystemTimeToDateTime(STime);
- Move(PTime, Buffer^, SizeOf(PTime));
- end;
- procedure TIBQuery.GetFloat(CurrBuff, Buffer : pointer; Field : TField);
- var
- Ext : extended;
- Dbl : double;
- Sin : single;
- begin
- case Field.Size of
- 4 :
- begin
- Move(CurrBuff^, Sin, 4);
- Ext := Sin;
- end;
- 8 :
- begin
- Move(CurrBuff^, Dbl, 8);
- Ext := Dbl;
- end;
- 10: Move(CurrBuff^, Ext, 10);
- end;
- Move(Ext, Buffer^, 10);
- end;
- function TIBQuery.AllocRecordBuffer: PChar;
- begin
- Result := AllocMem(FBufferSize);
- end;
- procedure TIBQuery.FreeRecordBuffer(var Buffer: PChar);
- begin
- FreeMem(Buffer);
- end;
- procedure TIBQuery.GetBookmarkData(Buffer: PChar; Data: Pointer);
- begin
- PInteger(Data)^ := PIBBookmark(Buffer + FRecordSize)^.BookmarkData;
- end;
- function TIBQuery.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
- begin
- Result := PIBBookmark(Buffer + FRecordSize)^.BookmarkFlag;
- end;
- function TIBQuery.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
- var
- x : longint;
- b : longint;
- CurrBuff : PChar;
- begin
- Result := False;
- CurrBuff := ActiveBuffer;
- for x := 0 to FSQLDA^.SQLD - 1 do
- begin
- {$R-}
- if (Field.FieldName = FSQLDA^.SQLVar[x].SQLName) then
- begin
- case Field.DataType of
- ftInteger :
- begin
- b := 0;
- Move(b, Buffer^, 4);
- Move(CurrBuff^, Buffer^, Field.Size);
- end;
- ftDate, ftTime, ftDateTime:
- GetDateTime(CurrBuff, Buffer, FSQLDA^.SQLVar[x].SQLType);
- ftString :
- begin
- Move(CurrBuff^, Buffer^, Field.Size);
- PChar(Buffer + Field.Size)^ := #0;
- end;
- ftFloat :
- GetFloat(CurrBuff, Buffer, Field);
- end;
- Result := True;
- Break;
- end
- else Inc(CurrBuff, FSQLDA^.SQLVar[x].SQLLen);
- {$R+}
- end;
- end;
- function TIBQuery.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
- begin
- if FStatementType <> stSelect then
- begin
- Result := grEOF;
- Exit;
- end;
- if FIsEOF then
- Result := grEOF
- else begin
- Result := grOK;
- case GetMode of
- gmPrior :
- if FCurrentRecord <= 0 then
- begin
- Result := grBOF;
- FCurrentRecord := -1;
- end
- else Dec(FCurrentRecord);
- gmCurrent :
- if (FCurrentRecord < 0) or (FCurrentRecord >= RecordCount) then
- Result := grError;
- gmNext :
- if FCurrentRecord >= (RecordCount - 1) then
- begin
- Result := LoadBufferFromSQLDA(Buffer);
- if Result = grOK then
- begin
- Inc(FCurrentRecord);
- Inc(FRecordCount);
- end;
- end
- else Inc(FCurrentRecord);
- end;
- end;
- if Result = grOK then
- begin
- with PIBBookmark(Buffer + FRecordSize)^ do
- begin
- BookmarkData := FCurrentRecord;
- BookmarkFlag := bfCurrent;
- end;
- end
- else if (Result = grError) then
- DatabaseError('No record');
- end;
- function TIBQuery.GetRecordCount: integer;
- begin
- Result := FRecordCount;
- end;
- function TIBQuery.GetRecordSize: Word;
- begin
- Result := FRecordSize;
- end;
- procedure TIBQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
- begin
- // not implemented - sql dataset
- end;
- procedure TIBQuery.InternalClose;
- begin
- FreeFldBuffers;
- FreeStatement;
- if DefaultFields then
- DestroyFields;
- FIsEOF := False;
- FCurrentRecord := -1;
- FBufferSize := 0;
- FRecordSize := 0;
- FRecordCount:= 0;
- FOpen:=False;
- end;
- procedure TIBQuery.InternalDelete;
- begin
- // not implemented - sql dataset
- end;
- procedure TIBQuery.InternalFirst;
- begin
- FCurrentRecord := -1;
- end;
- procedure TIBQuery.InternalGotoBookmark(ABookmark: Pointer);
- begin
- FCurrentRecord := PInteger(ABookmark)^;
- end;
- procedure TIBQuery.InternalHandleException;
- begin
- end;
- procedure TIBQuery.InternalInitFieldDefs;
- var
- x : integer;
- lenset : boolean;
- TransLen : word;
- TransType : TFieldType;
- begin
- if FLoadingFieldDefs then
- Exit;
- FLoadingFieldDefs := True;
- try
- FieldDefs.Clear;
- {$R-}
- for x := 0 to FSQLDA^.SQLD - 1 do
- begin
- TranslateFldType(FSQLDA^.SQLVar[x].SQLType, FSQLDA^.SQLVar[x].SQLLen, lenset,
- TransType, TransLen);
- TFieldDef.Create(FieldDefs, FSQLDA^.SQLVar[x].SQLName, TransType,
- TransLen, False, (x + 1));
- end;
- {$R+}
- finally
- FLoadingFieldDefs := False;
- end;
- end;
- procedure TIBQuery.InternalInitRecord(Buffer: PChar);
- begin
- FillChar(Buffer^, FBufferSize, #0);
- end;
- procedure TIBQuery.InternalLast;
- begin
- FCurrentRecord := RecordCount;
- end;
- procedure TIBQuery.InternalOpen;
- begin
- try
- AllocStatement;
- PrepareStatement;
- GetStatementType;
- if FStatementType in [stSelect] then
- begin
- DescribeStatement;
- AllocFldBuffers;
- Execute;
- FOpen:=True;
- InternalInitFieldDefs;
- if DefaultFields then
- CreateFields;
- SetFieldSizes;
- BindFields(True);
- end
- else Execute;
- except
- on E:Exception do
- raise;
- end;
- end;
- procedure TIBQuery.InternalPost;
- begin
- // not implemented - sql dataset
- end;
- procedure TIBQuery.InternalSetToRecord(Buffer: PChar);
- begin
- FCurrentRecord := PIBBookmark(Buffer + FRecordSize)^.BookmarkData;
- end;
- function TIBQuery.IsCursorOpen: Boolean;
- begin
- Result := FOpen;
- end;
- procedure TIBQuery.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
- begin
- PIBBookmark(Buffer + FRecordSize)^.BookmarkFlag := Value;
- end;
- procedure TIBQuery.SetBookmarkData(Buffer: PChar; Data: Pointer);
- begin
- PIBBookmark(Buffer + FRecordSize)^.BookmarkData := PInteger(Data)^;
- end;
- procedure TIBQuery.SetFieldData(Field: TField; Buffer: Pointer);
- begin
- end;
- // public part
- procedure TIBQuery.ExecSQL;
- begin
- AllocStatement;
- try
- PrepareStatement;
- GetStatementType;
- Execute;
- finally
- FreeStatement;
- end;
- end;
- constructor TIBQuery.Create(AOwner : TComponent);
- begin
- inherited Create(AOwner);
- FSQL := TStringList.Create;
- FCurrentRecord := -1;
- AllocSQLDA(10);
- end;
- destructor TIBQuery.Destroy;
- begin
- if Active then Close;
- FSQL.Free;
- inherited Destroy;
- FreeMem(FSQLDA);
- end;
- { TIBStoredProc }
- end.
|