2
0

ibconnection.pp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039
  1. unit IBConnection;
  2. {$mode objfpc}{$H+}
  3. {$Define LinkDynamically}
  4. interface
  5. uses
  6. Classes, SysUtils, sqldb, db, math, dbconst,
  7. {$IfDef LinkDynamically}
  8. ibase60dyn;
  9. {$Else}
  10. ibase60;
  11. {$EndIf}
  12. type
  13. EIBDatabaseError = class(EDatabaseError)
  14. public
  15. GDSErrorCode : Longint;
  16. end;
  17. TIBCursor = Class(TSQLCursor)
  18. protected
  19. Status : array [0..19] of ISC_STATUS;
  20. Statement : pointer;
  21. SQLDA : PXSQLDA;
  22. in_SQLDA : PXSQLDA;
  23. ParamBinding : array of integer;
  24. end;
  25. TIBTrans = Class(TSQLHandle)
  26. protected
  27. TransactionHandle : pointer;
  28. TPB : string; // Transaction parameter buffer
  29. Status : array [0..19] of ISC_STATUS;
  30. end;
  31. TIBConnection = class (TSQLConnection)
  32. private
  33. FSQLDatabaseHandle : pointer;
  34. FStatus : array [0..19] of ISC_STATUS;
  35. FDialect : integer;
  36. procedure SetDBDialect;
  37. procedure AllocSQLDA(var aSQLDA : PXSQLDA;Count : integer);
  38. procedure TranslateFldType(SQLType, SQLLen, SQLScale : integer; var LensSet : boolean;
  39. var TrType : TFieldType; var TrLen : word);
  40. // conversion methods
  41. procedure GetDateTime(CurrBuff, Buffer : pointer; AType : integer);
  42. procedure SetDateTime(CurrBuff: pointer; PTime : TDateTime; AType : integer);
  43. procedure GetFloat(CurrBuff, Buffer : pointer; Field : TFieldDef);
  44. procedure SetFloat(CurrBuff: pointer; Dbl: Double; Size: integer);
  45. procedure CheckError(ProcName : string; Status : array of ISC_STATUS);
  46. function getMaxBlobSize(blobHandle : TIsc_Blob_Handle) : longInt;
  47. procedure SetParameters(cursor : TSQLCursor;AParams : TParams);
  48. procedure FreeSQLDABuffer(var aSQLDA : PXSQLDA);
  49. protected
  50. procedure DoInternalConnect; override;
  51. procedure DoInternalDisconnect; override;
  52. function GetHandle : pointer; override;
  53. Function AllocateCursorHandle : TSQLCursor; override;
  54. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  55. Function AllocateTransactionHandle : TSQLHandle; override;
  56. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); override;
  57. procedure UnPrepareStatement(cursor : TSQLCursor); override;
  58. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  59. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); override;
  60. procedure AddFieldDefs(cursor: TSQLCursor;FieldDefs : TfieldDefs); override;
  61. function Fetch(cursor : TSQLCursor) : boolean; override;
  62. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer) : boolean; override;
  63. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  64. function Commit(trans : TSQLHandle) : boolean; override;
  65. function RollBack(trans : TSQLHandle) : boolean; override;
  66. function StartdbTransaction(trans : TSQLHandle; AParams : string) : boolean; override;
  67. procedure CommitRetaining(trans : TSQLHandle); override;
  68. procedure RollBackRetaining(trans : TSQLHandle); override;
  69. procedure UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string); override;
  70. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
  71. function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
  72. public
  73. constructor Create(AOwner : TComponent); override;
  74. published
  75. property Dialect : integer read FDialect write FDialect;
  76. property DatabaseName;
  77. property KeepConnection;
  78. property LoginPrompt;
  79. property Params;
  80. property OnLogin;
  81. end;
  82. implementation
  83. uses strutils;
  84. type
  85. TTm = packed record
  86. tm_sec : longint;
  87. tm_min : longint;
  88. tm_hour : longint;
  89. tm_mday : longint;
  90. tm_mon : longint;
  91. tm_year : longint;
  92. tm_wday : longint;
  93. tm_yday : longint;
  94. tm_isdst : longint;
  95. __tm_gmtoff : longint;
  96. __tm_zone : Pchar;
  97. end;
  98. procedure TIBConnection.CheckError(ProcName : string; Status : array of ISC_STATUS);
  99. var
  100. buf : array [0..1024] of char;
  101. p : pointer;
  102. Msg : string;
  103. E : EIBDatabaseError;
  104. begin
  105. if ((Status[0] = 1) and (Status[1] <> 0)) then
  106. begin
  107. p := @Status;
  108. msg := '';
  109. while isc_interprete(Buf, @p) > 0 do
  110. Msg := Msg + LineEnding +' -' + StrPas(Buf);
  111. E := EIBDatabaseError.CreateFmt('%s : %s : %s',[self.Name,ProcName,Msg]);
  112. E.GDSErrorCode := Status[1];
  113. Raise E;
  114. end;
  115. end;
  116. constructor TIBConnection.Create(AOwner : TComponent);
  117. begin
  118. inherited;
  119. FConnOptions := FConnOptions + [sqSupportParams];
  120. end;
  121. function TIBConnection.GetTransactionHandle(trans : TSQLHandle): pointer;
  122. begin
  123. Result := (trans as TIBtrans).TransactionHandle;
  124. end;
  125. function TIBConnection.Commit(trans : TSQLHandle) : boolean;
  126. begin
  127. result := false;
  128. with (trans as TIBTrans) do
  129. if isc_commit_transaction(@Status, @TransactionHandle) <> 0 then
  130. CheckError('Commit', Status)
  131. else result := true;
  132. end;
  133. function TIBConnection.RollBack(trans : TSQLHandle) : boolean;
  134. begin
  135. result := false;
  136. if isc_rollback_transaction(@TIBTrans(trans).Status, @TIBTrans(trans).TransactionHandle) <> 0 then
  137. CheckError('Rollback', TIBTrans(trans).Status)
  138. else result := true;
  139. end;
  140. function TIBConnection.StartDBTransaction(trans : TSQLHandle;AParams : String) : boolean;
  141. var
  142. DBHandle : pointer;
  143. tr : TIBTrans;
  144. i : integer;
  145. s : string;
  146. begin
  147. result := false;
  148. DBHandle := GetHandle;
  149. tr := trans as TIBtrans;
  150. with tr do
  151. begin
  152. TPB := chr(isc_tpb_version3);
  153. i := 1;
  154. s := ExtractSubStr(AParams,i,stdWordDelims);
  155. while s <> '' do
  156. begin
  157. if s='isc_tpb_write' then TPB := TPB + chr(isc_tpb_write)
  158. else if s='isc_tpb_read' then TPB := TPB + chr(isc_tpb_read)
  159. else if s='isc_tpb_consistency' then TPB := TPB + chr(isc_tpb_consistency)
  160. else if s='isc_tpb_concurrency' then TPB := TPB + chr(isc_tpb_concurrency)
  161. else if s='isc_tpb_read_committed' then TPB := TPB + chr(isc_tpb_read_committed)
  162. else if s='isc_tpb_rec_version' then TPB := TPB + chr(isc_tpb_rec_version)
  163. else if s='isc_tpb_no_rec_version' then TPB := TPB + chr(isc_tpb_no_rec_version)
  164. else if s='isc_tpb_wait' then TPB := TPB + chr(isc_tpb_wait)
  165. else if s='isc_tpb_nowait' then TPB := TPB + chr(isc_tpb_nowait)
  166. else if s='isc_tpb_shared' then TPB := TPB + chr(isc_tpb_shared)
  167. else if s='isc_tpb_protected' then TPB := TPB + chr(isc_tpb_protected)
  168. else if s='isc_tpb_exclusive' then TPB := TPB + chr(isc_tpb_exclusive)
  169. else if s='isc_tpb_lock_read' then TPB := TPB + chr(isc_tpb_lock_read)
  170. else if s='isc_tpb_lock_write' then TPB := TPB + chr(isc_tpb_lock_write)
  171. else if s='isc_tpb_verb_time' then TPB := TPB + chr(isc_tpb_verb_time)
  172. else if s='isc_tpb_commit_time' then TPB := TPB + chr(isc_tpb_commit_time)
  173. else if s='isc_tpb_ignore_limbo' then TPB := TPB + chr(isc_tpb_ignore_limbo)
  174. else if s='isc_tpb_autocommit' then TPB := TPB + chr(isc_tpb_autocommit)
  175. else if s='isc_tpb_restart_requests' then TPB := TPB + chr(isc_tpb_restart_requests)
  176. else if s='isc_tpb_no_auto_undo' then TPB := TPB + chr(isc_tpb_no_auto_undo);
  177. s := ExtractSubStr(AParams,i,stdWordDelims);
  178. end;
  179. TransactionHandle := nil;
  180. if isc_start_transaction(@Status, @TransactionHandle, 1,
  181. [@DBHandle, Length(TPB), @TPB[1]]) <> 0 then
  182. CheckError('StartTransaction',Status)
  183. else Result := True;
  184. end;
  185. end;
  186. procedure TIBConnection.CommitRetaining(trans : TSQLHandle);
  187. begin
  188. with trans as TIBtrans do
  189. if isc_commit_retaining(@Status, @TransactionHandle) <> 0 then
  190. CheckError('CommitRetaining', Status);
  191. end;
  192. procedure TIBConnection.RollBackRetaining(trans : TSQLHandle);
  193. begin
  194. with trans as TIBtrans do
  195. if isc_rollback_retaining(@Status, @TransactionHandle) <> 0 then
  196. CheckError('RollBackRetaining', Status);
  197. end;
  198. procedure TIBConnection.DoInternalConnect;
  199. var
  200. DPB : string;
  201. ADatabaseName : String;
  202. begin
  203. {$IfDef LinkDynamically}
  204. InitialiseIBase60;
  205. {$EndIf}
  206. inherited dointernalconnect;
  207. DPB := chr(isc_dpb_version1);
  208. if (UserName <> '') then
  209. begin
  210. DPB := DPB + chr(isc_dpb_user_name) + chr(Length(UserName)) + UserName;
  211. if (Password <> '') then
  212. DPB := DPB + chr(isc_dpb_password) + chr(Length(Password)) + Password;
  213. end;
  214. if (Role <> '') then
  215. DPB := DPB + chr(isc_dpb_sql_role_name) + chr(Length(Role)) + Role;
  216. if Length(CharSet) > 0 then
  217. DPB := DPB + Chr(isc_dpb_lc_ctype) + Chr(Length(CharSet)) + CharSet;
  218. FSQLDatabaseHandle := nil;
  219. if HostName <> '' then ADatabaseName := HostName+':'+DatabaseName
  220. else ADatabaseName := DatabaseName;
  221. if isc_attach_database(@FStatus, Length(ADatabaseName), @ADatabaseName[1], @FSQLDatabaseHandle,
  222. Length(DPB), @DPB[1]) <> 0 then
  223. CheckError('DoInternalConnect', FStatus);
  224. SetDBDialect;
  225. end;
  226. procedure TIBConnection.DoInternalDisconnect;
  227. begin
  228. if not Connected then
  229. begin
  230. FSQLDatabaseHandle := nil;
  231. Exit;
  232. end;
  233. isc_detach_database(@FStatus[0], @FSQLDatabaseHandle);
  234. CheckError('Close', FStatus);
  235. {$IfDef LinkDynamically}
  236. ReleaseIBase60;
  237. {$EndIf}
  238. end;
  239. procedure TIBConnection.SetDBDialect;
  240. var
  241. x : integer;
  242. Len : integer;
  243. Buffer : string;
  244. ResBuf : array [0..39] of byte;
  245. begin
  246. Buffer := Chr(isc_info_db_sql_dialect) + Chr(isc_info_end);
  247. if isc_database_info(@FStatus, @FSQLDatabaseHandle, Length(Buffer),
  248. @Buffer[1], SizeOf(ResBuf), @ResBuf) <> 0 then
  249. CheckError('SetDBDialect', FStatus);
  250. x := 0;
  251. while x < 40 do
  252. case ResBuf[x] of
  253. isc_info_db_sql_dialect :
  254. begin
  255. Inc(x);
  256. Len := isc_vax_integer(@ResBuf[x], 2);
  257. Inc(x, 2);
  258. FDialect := isc_vax_integer(@ResBuf[x], Len);
  259. Inc(x, Len);
  260. end;
  261. isc_info_end : Break;
  262. end;
  263. end;
  264. procedure TIBConnection.AllocSQLDA(var aSQLDA : PXSQLDA;Count : integer);
  265. var x : shortint;
  266. begin
  267. FreeSQLDABuffer(aSQLDA);
  268. if count > -1 then
  269. begin
  270. reAllocMem(aSQLDA, XSQLDA_Length(Count));
  271. { Zero out the memory block to avoid problems with exceptions within the
  272. constructor of this class. }
  273. FillChar(aSQLDA^, XSQLDA_Length(Count), 0);
  274. aSQLDA^.Version := sqlda_version1;
  275. aSQLDA^.SQLN := Count;
  276. end
  277. else
  278. reAllocMem(aSQLDA,0);
  279. end;
  280. procedure TIBConnection.TranslateFldType(SQLType, SQLLen, SQLScale : integer; var LensSet : boolean;
  281. var TrType : TFieldType; var TrLen : word);
  282. begin
  283. LensSet := False;
  284. if SQLScale < 0 then
  285. begin
  286. if (SQLScale >= -4) and (SQLScale <= -1) then //in [-4..-1] then
  287. begin
  288. LensSet := True;
  289. TrLen := SQLLen;
  290. TrType := ftBCD
  291. end
  292. else
  293. TrType := ftFMTBcd;
  294. end
  295. else case (SQLType and not 1) of
  296. SQL_VARYING :
  297. begin
  298. LensSet := True;
  299. TrType := ftString;
  300. TrLen := SQLLen;
  301. end;
  302. SQL_TEXT :
  303. begin
  304. LensSet := True;
  305. TrType := ftString;
  306. TrLen := SQLLen;
  307. end;
  308. SQL_TYPE_DATE :
  309. TrType := ftDate{Time};
  310. SQL_TYPE_TIME :
  311. TrType := ftDateTime;
  312. SQL_TIMESTAMP :
  313. TrType := ftDateTime;
  314. SQL_ARRAY :
  315. begin
  316. TrType := ftArray;
  317. LensSet := true;
  318. TrLen := SQLLen;
  319. end;
  320. SQL_BLOB :
  321. begin
  322. TrType := ftBlob;
  323. LensSet := True;
  324. TrLen := SQLLen;
  325. end;
  326. SQL_SHORT :
  327. TrType := ftInteger;
  328. SQL_LONG :
  329. begin
  330. LensSet := True;
  331. TrLen := 0;
  332. TrType := ftInteger;
  333. end;
  334. SQL_INT64 :
  335. TrType := ftLargeInt;
  336. SQL_DOUBLE :
  337. begin
  338. LensSet := True;
  339. TrLen := SQLLen;
  340. TrType := ftFloat;
  341. end;
  342. SQL_FLOAT :
  343. begin
  344. LensSet := True;
  345. TrLen := SQLLen;
  346. TrType := ftFloat;
  347. end
  348. else
  349. begin
  350. LensSet := True;
  351. TrLen := 0;
  352. TrType := ftUnknown;
  353. end;
  354. end;
  355. end;
  356. Function TIBConnection.AllocateCursorHandle : TSQLCursor;
  357. var curs : TIBCursor;
  358. begin
  359. curs := TIBCursor.create;
  360. curs.sqlda := nil;
  361. curs.statement := nil;
  362. curs.FPrepared := False;
  363. AllocSQLDA(curs.SQLDA,0);
  364. AllocSQLDA(curs.in_SQLDA,0);
  365. result := curs;
  366. end;
  367. procedure TIBConnection.DeAllocateCursorHandle(var cursor : TSQLCursor);
  368. begin
  369. if assigned(cursor) then with cursor as TIBCursor do
  370. begin
  371. AllocSQLDA(SQLDA,-1);
  372. AllocSQLDA(in_SQLDA,-1);
  373. end;
  374. FreeAndNil(cursor);
  375. end;
  376. Function TIBConnection.AllocateTransactionHandle : TSQLHandle;
  377. begin
  378. result := TIBTrans.create;
  379. end;
  380. procedure TIBConnection.PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams);
  381. var dh : pointer;
  382. tr : pointer;
  383. p : pchar;
  384. x : shortint;
  385. i : integer;
  386. begin
  387. with cursor as TIBcursor do
  388. begin
  389. dh := GetHandle;
  390. if isc_dsql_allocate_statement(@Status, @dh, @Statement) <> 0 then
  391. CheckError('PrepareStatement', Status);
  392. tr := aTransaction.Handle;
  393. if assigned(AParams) and (AParams.count > 0) then
  394. buf := AParams.ParseSQL(buf,false,psInterbase,paramBinding);
  395. if isc_dsql_prepare(@Status, @tr, @Statement, 0, @Buf[1], Dialect, nil) <> 0 then
  396. CheckError('PrepareStatement', Status);
  397. FPrepared := True;
  398. if assigned(AParams) and (AParams.count > 0) then
  399. begin
  400. AllocSQLDA(in_SQLDA,Length(ParamBinding));
  401. if isc_dsql_describe_bind(@Status, @Statement, 1, in_SQLDA) <> 0 then
  402. CheckError('PrepareStatement', Status);
  403. if in_SQLDA^.SQLD > in_SQLDA^.SQLN then
  404. DatabaseError(SParameterCountIncorrect,self);
  405. {$R-}
  406. for x := 0 to in_SQLDA^.SQLD - 1 do with in_SQLDA^.SQLVar[x] do
  407. begin
  408. if ((SQLType and not 1) = SQL_VARYING) then
  409. SQLData := AllocMem(in_SQLDA^.SQLVar[x].SQLLen+2)
  410. else
  411. SQLData := AllocMem(in_SQLDA^.SQLVar[x].SQLLen);
  412. if (sqltype and 1) = 1 then New(SQLInd);
  413. end;
  414. {$R+}
  415. end;
  416. if FStatementType = stselect then
  417. begin
  418. FPrepared := False;
  419. if isc_dsql_describe(@Status, @Statement, 1, SQLDA) <> 0 then
  420. CheckError('PrepareSelect', Status);
  421. if SQLDA^.SQLD > SQLDA^.SQLN then
  422. begin
  423. AllocSQLDA(SQLDA,SQLDA^.SQLD);
  424. if isc_dsql_describe(@Status, @Statement, 1, SQLDA) <> 0 then
  425. CheckError('PrepareSelect', Status);
  426. end;
  427. {$R-}
  428. for x := 0 to SQLDA^.SQLD - 1 do with SQLDA^.SQLVar[x] do
  429. begin
  430. if ((SQLType and not 1) = SQL_VARYING) then
  431. SQLData := AllocMem(SQLDA^.SQLVar[x].SQLLen+2)
  432. else
  433. SQLData := AllocMem(SQLDA^.SQLVar[x].SQLLen);
  434. if (SQLType and 1) = 1 then New(SQLInd);
  435. end;
  436. {$R+}
  437. end;
  438. end;
  439. end;
  440. procedure TIBConnection.UnPrepareStatement(cursor : TSQLCursor);
  441. begin
  442. with cursor as TIBcursor do
  443. begin
  444. if isc_dsql_free_statement(@Status, @Statement, DSQL_Drop) <> 0 then
  445. CheckError('FreeStatement', Status);
  446. Statement := nil;
  447. FPrepared := False;
  448. end;
  449. end;
  450. procedure TIBConnection.FreeSQLDABuffer(var aSQLDA : PXSQLDA);
  451. var x : shortint;
  452. begin
  453. {$R-}
  454. if assigned(aSQLDA) then
  455. for x := 0 to aSQLDA^.SQLN - 1 do
  456. begin
  457. reAllocMem(aSQLDA^.SQLVar[x].SQLData,0);
  458. if assigned(aSQLDA^.SQLVar[x].sqlind) then
  459. begin
  460. Dispose(aSQLDA^.SQLVar[x].sqlind);
  461. aSQLDA^.SQLVar[x].sqlind := nil;
  462. end
  463. end;
  464. {$R+}
  465. end;
  466. procedure TIBConnection.FreeFldBuffers(cursor : TSQLCursor);
  467. begin
  468. with cursor as TIBCursor do
  469. begin
  470. FreeSQLDABuffer(SQLDA);
  471. FreeSQLDABuffer(in_SQLDA);
  472. end;
  473. end;
  474. procedure TIBConnection.Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams);
  475. var tr : pointer;
  476. begin
  477. tr := aTransaction.Handle;
  478. if Assigned(APArams) and (AParams.count > 0) then SetParameters(cursor, AParams);
  479. with cursor as TIBCursor do
  480. if isc_dsql_execute2(@Status, @tr, @Statement, 1, in_SQLDA, nil) <> 0 then
  481. CheckError('Execute', Status);
  482. end;
  483. procedure TIBConnection.AddFieldDefs(cursor: TSQLCursor;FieldDefs : TfieldDefs);
  484. var
  485. x : integer;
  486. lenset : boolean;
  487. TransLen : word;
  488. TransType : TFieldType;
  489. FD : TFieldDef;
  490. begin
  491. {$R-}
  492. with cursor as TIBCursor do
  493. begin
  494. for x := 0 to SQLDA^.SQLD - 1 do
  495. begin
  496. TranslateFldType(SQLDA^.SQLVar[x].SQLType, SQLDA^.SQLVar[x].SQLLen, SQLDA^.SQLVar[x].SQLScale,
  497. lenset, TransType, TransLen);
  498. FD := TFieldDef.Create(FieldDefs, SQLDA^.SQLVar[x].AliasName, TransType,
  499. TransLen, False, (x + 1));
  500. if TransType = ftBCD then FD.precision := SQLDA^.SQLVar[x].SQLLen;
  501. FD.DisplayName := SQLDA^.SQLVar[x].AliasName;
  502. end;
  503. end;
  504. {$R+}
  505. end;
  506. function TIBConnection.GetHandle: pointer;
  507. begin
  508. Result := FSQLDatabaseHandle;
  509. end;
  510. function TIBConnection.Fetch(cursor : TSQLCursor) : boolean;
  511. var
  512. retcode : integer;
  513. begin
  514. with cursor as TIBCursor do
  515. begin
  516. retcode := isc_dsql_fetch(@Status, @Statement, 1, SQLDA);
  517. if (retcode <> 0) and (retcode <> 100) then
  518. CheckError('Fetch', Status);
  519. end;
  520. Result := (retcode <> 100);
  521. end;
  522. procedure TIBConnection.SetParameters(cursor : TSQLCursor;AParams : TParams);
  523. var ParNr,SQLVarNr : integer;
  524. s : string;
  525. i : integer;
  526. li : LargeInt;
  527. currbuff : pchar;
  528. w : word;
  529. begin
  530. {$R-}
  531. with cursor as TIBCursor do for SQLVarNr := 0 to High(ParamBinding){AParams.count-1} do
  532. begin
  533. ParNr := ParamBinding[SQLVarNr];
  534. if AParams[ParNr].IsNull then
  535. begin
  536. If Assigned(in_sqlda^.SQLvar[SQLVarNr].SQLInd) then
  537. in_sqlda^.SQLvar[SQLVarNr].SQLInd^ := -1;
  538. end
  539. else
  540. begin
  541. if assigned(in_sqlda^.SQLvar[SQLVarNr].SQLInd) then in_sqlda^.SQLvar[SQLVarNr].SQLInd^ := 0;
  542. case AParams[ParNr].DataType of
  543. ftInteger :
  544. begin
  545. i := AParams[ParNr].AsInteger;
  546. {$R-}
  547. Move(i, in_sqlda^.SQLvar[SQLVarNr].SQLData^, in_SQLDA^.SQLVar[SQLVarNr].SQLLen);
  548. {$R+}
  549. end;
  550. ftString,ftFixedChar :
  551. begin
  552. {$R-}
  553. s := AParams[ParNr].AsString;
  554. w := length(s);
  555. if ((in_sqlda^.SQLvar[SQLVarNr].SQLType and not 1) = SQL_VARYING) then
  556. begin
  557. in_sqlda^.SQLvar[SQLVarNr].SQLLen := w;
  558. ReAllocMem(in_sqlda^.SQLvar[SQLVarNr].SQLData,in_SQLDA^.SQLVar[SQLVarNr].SQLLen+2);
  559. CurrBuff := in_sqlda^.SQLvar[SQLVarNr].SQLData;
  560. move(w,CurrBuff^,sizeof(w));
  561. inc(CurrBuff,2);
  562. end
  563. else
  564. CurrBuff := in_sqlda^.SQLvar[SQLVarNr].SQLData;
  565. Move(s[1], CurrBuff^, length(s));
  566. {$R+}
  567. end;
  568. ftDate, ftTime, ftDateTime:
  569. {$R-}
  570. SetDateTime(in_sqlda^.SQLvar[SQLVarNr].SQLData, AParams[ParNr].AsDateTime, in_SQLDA^.SQLVar[SQLVarNr].SQLType);
  571. {$R+}
  572. ftLargeInt:
  573. begin
  574. li := AParams[ParNr].AsLargeInt;
  575. {$R-}
  576. Move(li, in_sqlda^.SQLvar[SQLVarNr].SQLData^, in_SQLDA^.SQLVar[SQLVarNr].SQLLen);
  577. {$R+}
  578. end;
  579. ftFloat:
  580. {$R-}
  581. SetFloat(in_sqlda^.SQLvar[SQLVarNr].SQLData, AParams[ParNr].AsFloat, in_SQLDA^.SQLVar[SQLVarNr].SQLLen);
  582. {$R+}
  583. else
  584. DatabaseErrorFmt(SUnsupportedParameter,[Fieldtypenames[AParams[ParNr].DataType]],self);
  585. end {case}
  586. end;
  587. end;
  588. {$R+}
  589. end;
  590. function TIBConnection.LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer) : boolean;
  591. var
  592. x : integer;
  593. VarcharLen : word;
  594. CurrBuff : pchar;
  595. b : longint;
  596. c : currency;
  597. begin
  598. with cursor as TIBCursor do
  599. begin
  600. {$R-}
  601. for x := 0 to SQLDA^.SQLD - 1 do
  602. if SQLDA^.SQLVar[x].AliasName = FieldDef.Name then break;
  603. if SQLDA^.SQLVar[x].AliasName <> FieldDef.Name then
  604. DatabaseErrorFmt(SFieldNotFound,[FieldDef.Name],self);
  605. if assigned(SQLDA^.SQLVar[x].SQLInd) and (SQLDA^.SQLVar[x].SQLInd^ = -1) then
  606. result := false
  607. else
  608. begin
  609. with SQLDA^.SQLVar[x] do
  610. if ((SQLType and not 1) = SQL_VARYING) then
  611. begin
  612. Move(SQLData^, VarcharLen, 2);
  613. CurrBuff := SQLData + 2;
  614. end
  615. else
  616. begin
  617. CurrBuff := SQLData;
  618. VarCharLen := SQLDA^.SQLVar[x].SQLLen;
  619. end;
  620. Result := true;
  621. case FieldDef.DataType of
  622. ftBCD :
  623. begin
  624. c := 0;
  625. Move(CurrBuff^, c, SQLDA^.SQLVar[x].SQLLen);
  626. c := c*intpower(10,4+SQLDA^.SQLVar[x].SQLScale);
  627. Move(c, buffer^ , sizeof(c));
  628. end;
  629. ftInteger :
  630. begin
  631. b := 0;
  632. Move(b, Buffer^, sizeof(longint));
  633. Move(CurrBuff^, Buffer^, SQLDA^.SQLVar[x].SQLLen);
  634. end;
  635. ftLargeint :
  636. begin
  637. FillByte(buffer^,sizeof(LargeInt),0);
  638. Move(CurrBuff^, Buffer^, SQLDA^.SQLVar[x].SQLLen);
  639. end;
  640. ftDate, ftTime, ftDateTime:
  641. GetDateTime(CurrBuff, Buffer, SQLDA^.SQLVar[x].SQLType);
  642. ftString :
  643. begin
  644. Move(CurrBuff^, Buffer^, SQLDA^.SQLVar[x].SQLLen);
  645. PChar(Buffer + VarCharLen)^ := #0;
  646. end;
  647. ftFloat :
  648. GetFloat(CurrBuff, Buffer, FieldDef);
  649. ftBlob : begin // load the BlobIb in field's buffer
  650. FillByte(buffer^,sizeof(LargeInt),0);
  651. Move(CurrBuff^, Buffer^, SQLDA^.SQLVar[x].SQLLen);
  652. end
  653. else result := false;
  654. end;
  655. end;
  656. {$R+}
  657. end;
  658. end;
  659. procedure TIBConnection.GetDateTime(CurrBuff, Buffer : pointer; AType : integer);
  660. var
  661. CTime : TTm; // C struct time
  662. STime : TSystemTime; // System time
  663. PTime : TDateTime; // Pascal time
  664. begin
  665. case (AType and not 1) of
  666. SQL_TYPE_DATE :
  667. isc_decode_sql_date(PISC_DATE(CurrBuff), @CTime);
  668. SQL_TYPE_TIME :
  669. isc_decode_sql_time(PISC_TIME(CurrBuff), @CTime);
  670. SQL_TIMESTAMP :
  671. isc_decode_timestamp(PISC_TIMESTAMP(CurrBuff), @CTime);
  672. end;
  673. STime.Year := CTime.tm_year + 1900;
  674. STime.Month := CTime.tm_mon + 1;
  675. STime.Day := CTime.tm_mday;
  676. STime.Hour := CTime.tm_hour;
  677. STime.Minute := CTime.tm_min;
  678. STime.Second := CTime.tm_sec;
  679. STime.Millisecond := 0;
  680. PTime := SystemTimeToDateTime(STime);
  681. Move(PTime, Buffer^, SizeOf(PTime));
  682. end;
  683. procedure TIBConnection.SetDateTime(CurrBuff: pointer; PTime : TDateTime; AType : integer);
  684. var
  685. CTime : TTm; // C struct time
  686. STime : TSystemTime; // System time
  687. begin
  688. DateTimeToSystemTime(PTime,STime);
  689. CTime.tm_year := STime.Year - 1900;
  690. CTime.tm_mon := STime.Month -1;
  691. CTime.tm_mday := STime.Day;
  692. CTime.tm_hour := STime.Hour;
  693. CTime.tm_min := STime.Minute;
  694. CTime.tm_sec := STime.Second;
  695. case (AType and not 1) of
  696. SQL_TYPE_DATE :
  697. isc_encode_sql_date(@CTime, PISC_DATE(CurrBuff));
  698. SQL_TYPE_TIME :
  699. isc_encode_sql_time(@CTime, PISC_TIME(CurrBuff));
  700. SQL_TIMESTAMP :
  701. isc_encode_timestamp(@CTime, PISC_TIMESTAMP(CurrBuff));
  702. end;
  703. end;
  704. function TIBConnection.GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  705. var s : string;
  706. begin
  707. case SchemaType of
  708. stTables : s := 'select '+
  709. 'rdb$relation_id as recno, '+
  710. '''' + DatabaseName + ''' as catalog_name, '+
  711. ''''' as schema_name, '+
  712. 'rdb$relation_name as table_name, '+
  713. '0 as table_type '+
  714. 'from '+
  715. 'rdb$relations '+
  716. 'where '+
  717. '(rdb$system_flag = 0 or rdb$system_flag is null) ' + // and rdb$view_blr is null
  718. 'order by rdb$relation_name';
  719. stSysTables : s := 'select '+
  720. 'rdb$relation_id as recno, '+
  721. '''' + DatabaseName + ''' as catalog_name, '+
  722. ''''' as schema_name, '+
  723. 'rdb$relation_name as table_name, '+
  724. '0 as table_type '+
  725. 'from '+
  726. 'rdb$relations '+
  727. 'where '+
  728. '(rdb$system_flag > 0) ' + // and rdb$view_blr is null
  729. 'order by rdb$relation_name';
  730. stProcedures : s := 'select '+
  731. 'rdb$procedure_id as recno, '+
  732. '''' + DatabaseName + ''' as catalog_name, '+
  733. ''''' as schema_name, '+
  734. 'rdb$procedure_name as proc_name, '+
  735. '0 as proc_type, '+
  736. 'rdb$procedure_inputs as in_params, '+
  737. 'rdb$procedure_outputs as out_params '+
  738. 'from '+
  739. 'rdb$procedures '+
  740. 'WHERE '+
  741. '(rdb$system_flag = 0 or rdb$system_flag is null)';
  742. stColumns : s := 'select '+
  743. 'rdb$field_id as recno, '+
  744. '''' + DatabaseName + ''' as catalog_name, '+
  745. ''''' as schema_name, '+
  746. 'rdb$relation_name as table_name, '+
  747. 'rdb$field_name as column_name, '+
  748. 'rdb$field_position as column_position, '+
  749. '0 as column_type, '+
  750. '0 as column_datatype, '+
  751. ''''' as column_typename, '+
  752. '0 as column_subtype, '+
  753. '0 as column_precision, '+
  754. '0 as column_scale, '+
  755. '0 as column_length, '+
  756. '0 as column_nullable '+
  757. 'from '+
  758. 'rdb$relation_fields '+
  759. 'WHERE '+
  760. '(rdb$system_flag = 0 or rdb$system_flag is null) and (rdb$relation_name = ''' + Uppercase(SchemaObjectName) + ''') ' +
  761. 'order by rdb$field_name';
  762. else
  763. DatabaseError(SMetadataUnavailable)
  764. end; {case}
  765. result := s;
  766. end;
  767. procedure TIBConnection.UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string);
  768. var qry : TSQLQuery;
  769. begin
  770. if not assigned(Transaction) then
  771. DatabaseError(SErrConnTransactionnSet);
  772. qry := tsqlquery.Create(nil);
  773. qry.transaction := Transaction;
  774. qry.database := Self;
  775. with qry do
  776. begin
  777. ReadOnly := True;
  778. sql.clear;
  779. sql.add('select '+
  780. 'ind.rdb$index_name, '+
  781. 'ind.rdb$relation_name, '+
  782. 'ind.rdb$unique_flag, '+
  783. 'ind_seg.rdb$field_name, '+
  784. 'rel_con.rdb$constraint_type '+
  785. 'from '+
  786. 'rdb$index_segments ind_seg, '+
  787. 'rdb$indices ind '+
  788. 'left outer join '+
  789. 'rdb$relation_constraints rel_con '+
  790. 'on '+
  791. 'rel_con.rdb$index_name = ind.rdb$index_name '+
  792. 'where '+
  793. '(ind_seg.rdb$index_name = ind.rdb$index_name) and '+
  794. '(ind.rdb$relation_name=''' + UpperCase(TableName) +''') '+
  795. 'order by '+
  796. 'ind.rdb$index_name;');
  797. open;
  798. end;
  799. while not qry.eof do with IndexDefs.AddIndexDef do
  800. begin
  801. Name := trim(qry.fields[0].asstring);
  802. Fields := trim(qry.Fields[3].asstring);
  803. If qry.fields[4].asstring = 'PRIMARY KEY' then options := options + [ixPrimary];
  804. If qry.fields[2].asinteger = 1 then options := options + [ixUnique];
  805. qry.next;
  806. while (name = qry.fields[0].asstring) and (not qry.eof) do
  807. begin
  808. Fields := Fields + ';' + trim(qry.Fields[3].asstring);
  809. qry.next;
  810. end;
  811. end;
  812. qry.close;
  813. qry.free;
  814. end;
  815. procedure TIBConnection.SetFloat(CurrBuff: pointer; Dbl: Double; Size: integer);
  816. var
  817. Ext : extended;
  818. Sin : single;
  819. begin
  820. case Size of
  821. 4 :
  822. begin
  823. Sin := Dbl;
  824. Move(Sin, CurrBuff^, 4);
  825. end;
  826. 8 :
  827. begin
  828. Move(Dbl, CurrBuff^, 8);
  829. end;
  830. 10:
  831. begin
  832. Ext := Dbl;
  833. Move(Ext, CurrBuff^, 10);
  834. end;
  835. end;
  836. end;
  837. procedure TIBConnection.GetFloat(CurrBuff, Buffer : pointer; Field : TFieldDef);
  838. var
  839. Ext : extended;
  840. Dbl : double;
  841. Sin : single;
  842. begin
  843. case Field.Size of
  844. 4 :
  845. begin
  846. Move(CurrBuff^, Sin, 4);
  847. Dbl := Sin;
  848. end;
  849. 8 :
  850. begin
  851. Move(CurrBuff^, Dbl, 8);
  852. end;
  853. 10:
  854. begin
  855. Move(CurrBuff^, Ext, 10);
  856. Dbl := double(Ext);
  857. end;
  858. end;
  859. Move(Dbl, Buffer^, 8);
  860. end;
  861. function TIBConnection.getMaxBlobSize(blobHandle : TIsc_Blob_Handle) : longInt;
  862. var
  863. iscInfoBlobMaxSegment : byte = isc_info_blob_max_segment;
  864. blobInfo : array[0..50] of byte;
  865. begin
  866. if isc_blob_info(@Fstatus, @blobHandle, sizeof(iscInfoBlobMaxSegment), @iscInfoBlobMaxSegment, sizeof(blobInfo) - 2, @blobInfo) <> 0 then
  867. CheckError('isc_blob_info', FStatus);
  868. if blobInfo[0] = isc_info_blob_max_segment then
  869. begin
  870. result := isc_vax_integer(pchar(@blobInfo[3]), isc_vax_integer(pchar(@blobInfo[1]), 2));
  871. end
  872. else
  873. CheckError('isc_blob_info', FStatus);
  874. end;
  875. function TIBConnection.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
  876. const
  877. isc_segstr_eof = 335544367; // It's not defined in ibase60 but in ibase40. Would it be better to define in ibase60?
  878. var
  879. mStream : TMemoryStream;
  880. blobHandle : Isc_blob_Handle;
  881. blobSegment : pointer;
  882. blobSegLen : smallint;
  883. maxBlobSize : longInt;
  884. TransactionHandle : pointer;
  885. blobId : ISC_QUAD;
  886. begin
  887. result := nil;
  888. if mode = bmRead then begin
  889. if not field.getData(@blobId) then
  890. exit;
  891. if not assigned(Transaction) then
  892. DatabaseError(SErrConnTransactionnSet);
  893. TransactionHandle := transaction.Handle;
  894. blobHandle := nil;
  895. if isc_open_blob(@FStatus, @FSQLDatabaseHandle, @TransactionHandle, @blobHandle, @blobId) <> 0 then
  896. CheckError('TIBConnection.CreateBlobStream', FStatus);
  897. maxBlobSize := getMaxBlobSize(blobHandle);
  898. blobSegment := AllocMem(maxBlobSize);
  899. mStream := TMemoryStream.create;
  900. while (isc_get_segment(@FStatus, @blobHandle, @blobSegLen, maxBlobSize, blobSegment) = 0) do begin
  901. mStream.writeBuffer(blobSegment^, blobSegLen);
  902. end;
  903. freemem(blobSegment);
  904. mStream.seek(0,soFromBeginning);
  905. if FStatus[1] = isc_segstr_eof then
  906. begin
  907. if isc_close_blob(@FStatus, @blobHandle) <> 0 then
  908. CheckError('TIBConnection.CreateBlobStream isc_close_blob', FStatus);
  909. end
  910. else
  911. CheckError('TIBConnection.CreateBlobStream isc_get_segment', FStatus);
  912. result := mStream;
  913. end;
  914. end;
  915. end.