oracleconnection.pp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. unit oracleconnection;
  2. {$mode objfpc}{$H+}
  3. {$Define LinkDynamically}
  4. interface
  5. uses
  6. Classes, SysUtils, sqldb,db,dbconst,
  7. {$IfDef LinkDynamically}
  8. ocidyn,
  9. {$ELSE}
  10. oci,
  11. {$ENDIF}
  12. oratypes;
  13. const
  14. DefaultTimeOut = 60;
  15. type
  16. EOraDatabaseError = class(EDatabaseError)
  17. public
  18. ORAErrorCode : Longint;
  19. end;
  20. TOracleTrans = Class(TSQLHandle)
  21. protected
  22. FOciSvcCtx : POCISvcCtx;
  23. FOciTrans : POCITrans;
  24. FOciFlags : ub4;
  25. public
  26. destructor Destroy(); override;
  27. end;
  28. TOraFieldBuf = record
  29. Buffer : pointer;
  30. Ind : sb2;
  31. Len : ub4;
  32. Size : ub4;
  33. end;
  34. TOracleCursor = Class(TSQLCursor)
  35. protected
  36. FOciStmt : POCIStmt;
  37. FieldBuffers : array of TOraFieldBuf;
  38. ParamBuffers : array of TOraFieldBuf;
  39. end;
  40. { TOracleConnection }
  41. TOracleConnection = class (TSQLConnection)
  42. private
  43. FOciEnvironment : POciEnv;
  44. FOciError : POCIError;
  45. FOciServer : POCIServer;
  46. FOciUserSession : POCISession;
  47. FUserMem : pointer;
  48. procedure HandleError;
  49. procedure GetParameters(cursor : TSQLCursor;AParams : TParams);
  50. procedure SetParameters(cursor : TSQLCursor;AParams : TParams);
  51. protected
  52. // - Connect/disconnect
  53. procedure DoInternalConnect; override;
  54. procedure DoInternalDisconnect; override;
  55. // - Handle (de)allocation
  56. function AllocateCursorHandle:TSQLCursor; override;
  57. procedure DeAllocateCursorHandle(var cursor:TSQLCursor); override;
  58. function AllocateTransactionHandle:TSQLHandle; override;
  59. // - Statement handling
  60. procedure PrepareStatement(cursor:TSQLCursor; ATransaction:TSQLTransaction; buf:string; AParams:TParams); override;
  61. procedure UnPrepareStatement(cursor:TSQLCursor); override;
  62. // - Transaction handling
  63. procedure InternalStartDBTransaction(trans:TOracleTrans);
  64. function GetTransactionHandle(trans:TSQLHandle):pointer; override;
  65. function StartDBTransaction(trans:TSQLHandle; AParams:string):boolean; override;
  66. function Commit(trans:TSQLHandle):boolean; override;
  67. function Rollback(trans:TSQLHandle):boolean; override;
  68. procedure CommitRetaining(trans:TSQLHandle); override;
  69. procedure RollbackRetaining(trans:TSQLHandle); override;
  70. // - Statement execution
  71. procedure Execute(cursor:TSQLCursor; ATransaction:TSQLTransaction; AParams:TParams); override;
  72. function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
  73. // - Result retrieval
  74. procedure AddFieldDefs(cursor:TSQLCursor; FieldDefs:TFieldDefs); override;
  75. function Fetch(cursor:TSQLCursor):boolean; override;
  76. function LoadField(cursor:TSQLCursor; FieldDef:TFieldDef; buffer:pointer; out CreateBlob : boolean):boolean; override;
  77. // procedure LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction); override;
  78. procedure FreeFldBuffers(cursor:TSQLCursor); override;
  79. procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); override;
  80. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
  81. public
  82. constructor Create(AOwner : TComponent); override;
  83. end;
  84. { TOracleConnectionDef }
  85. TOracleConnectionDef = Class(TConnectionDef)
  86. Class Function TypeName : String; override;
  87. Class Function ConnectionClass : TSQLConnectionClass; override;
  88. Class Function Description : String; override;
  89. Class Function DefaultLibraryName : String; override;
  90. Class Function LoadFunction : TLibraryLoadFunction; override;
  91. Class Function UnLoadFunction : TLibraryUnLoadFunction; override;
  92. Class Function LoadedLibraryName: string; override;
  93. end;
  94. implementation
  95. uses
  96. math, StrUtils, FmtBCD;
  97. ResourceString
  98. SErrEnvCreateFailed = 'The creation of an Oracle environment failed.';
  99. SErrHandleAllocFailed = 'The allocation of the error handle failed.';
  100. SErrOracle = 'Oracle returned error %s:';
  101. //callback functions
  102. function cbf_no_data(ictxp:Pdvoid; bindp:POCIBind; iter:ub4; index:ub4; bufpp:PPdvoid;
  103. alenp:Pub4; piecep:Pub1; indp:PPdvoid):sb4;cdecl;
  104. begin
  105. bufpp^ := nil;
  106. alenp^ := 0;
  107. indp^ := nil;
  108. piecep^ := OCI_ONE_PIECE;
  109. result:=OCI_CONTINUE;
  110. end;
  111. function cbf_get_data(octxp:Pdvoid; bindp:POCIBind; iter:ub4; index:ub4; bufpp:PPdvoid;
  112. alenp:PPub4; piecep:Pub1; indp:PPdvoid; rcodep:PPub2):sb4;cdecl;
  113. begin
  114. //only 1 row can be stored. No support for multiple rows. When multiple rows, only last is kept.
  115. bufpp^:=TOraFieldBuf(octxp^).Buffer;
  116. indp^ := @TOraFieldBuf(octxp^).Ind;
  117. TOraFieldBuf(octxp^).Len:=TOraFieldBuf(octxp^).Size; //reset size to full buffer
  118. alenp^ := @TOraFieldBuf(octxp^).Len;
  119. rcodep^:=nil;
  120. piecep^ := OCI_ONE_PIECE;
  121. result:=OCI_CONTINUE;
  122. end;
  123. //conversions
  124. Procedure FmtBCD2Nvu(bcd:tBCD;b:pByte);
  125. var
  126. i,j,cnt : integer;
  127. nibbles : array [0..maxfmtbcdfractionsize-1] of byte;
  128. exp : shortint;
  129. bb : byte;
  130. begin
  131. fillchar(b[0],22,#0);
  132. if BCDPrecision(bcd)=0 then // zero, special case
  133. begin
  134. b[0]:=1;
  135. b[1]:=$80;
  136. end
  137. else
  138. begin
  139. if (BCDPrecision(bcd)-BCDScale(bcd)) mod 2 <>0 then // odd number before decimal point
  140. begin
  141. nibbles[0]:=0;
  142. j:=1;
  143. end
  144. else
  145. j:=0;
  146. for i:=0 to bcd.Precision -1 do
  147. if i mod 2 =0 then
  148. nibbles[i+j]:=bcd.Fraction[i div 2] shr 4
  149. else
  150. nibbles[i+j]:=bcd.Fraction[i div 2] and $0f;
  151. nibbles[bcd.Precision+j]:=0; // make sure last nibble is also 0 in case we have odd scale
  152. exp:=(BCDPrecision(bcd)-BCDScale(bcd)+1) div 2;
  153. cnt:=exp+(BCDScale(bcd)+1) div 2;
  154. // to avoid "ora 01438: value larger than specified precision allowed for this column"
  155. // remove trailing zeros (scale < 0)
  156. while (nibbles[cnt*2-2]*10+nibbles[cnt*2-1])=0 do
  157. cnt:=cnt-1;
  158. // and remove leading zeros (scale > precision)
  159. j:=0;
  160. while (nibbles[j*2]*10+nibbles[j*2+1])=0 do
  161. begin
  162. j:=j+1;
  163. exp:=exp-1;
  164. end;
  165. if IsBCDNegative(bcd) then
  166. begin
  167. b[0]:=cnt-j+1;
  168. b[1]:=not(exp+64) and $7f ;
  169. for i:=j to cnt-1 do
  170. begin
  171. bb:=nibbles[i*2]*10+nibbles[i*2+1];
  172. b[2+i-j]:=101-bb;
  173. end;
  174. if 2+cnt-j<22 then // add a 102 at the end of the number if place left.
  175. begin
  176. b[0]:=b[0]+1;
  177. b[2+cnt-j]:=102;
  178. end;
  179. end
  180. else
  181. begin
  182. b[0]:=cnt-j+1;
  183. b[1]:=(exp+64) or $80 ;
  184. for i:=j to cnt-1 do
  185. begin
  186. bb:=nibbles[i*2]*10+nibbles[i*2+1];
  187. b[2+i-j]:=1+bb;
  188. end;
  189. end;
  190. end;
  191. end;
  192. function Nvu2FmtBCE(b:pbyte):tBCD;
  193. var
  194. i,j : integer;
  195. bb,size : byte;
  196. exp : shortint;
  197. nibbles : array [0..maxfmtbcdfractionsize-1] of byte;
  198. scale : integer;
  199. begin
  200. size := b[0];
  201. if (size=1) and (b[1]=$80) then // special representation for 0
  202. result:=IntegerToBCD(0)
  203. else
  204. begin
  205. result.SignSpecialPlaces:=0; //sign positive, non blank, scale 0
  206. result.Precision:=1; //BCDNegate works only if Precision <>0
  207. if (b[1] and $80)=$80 then // then the number is positive
  208. begin
  209. exp := (b[1] and $7f)-65;
  210. for i := 0 to size-2 do
  211. begin
  212. bb := b[i+2]-1;
  213. nibbles[i*2]:=bb div 10;
  214. nibbles[i*2+1]:=(bb mod 10);
  215. end;
  216. end
  217. else
  218. begin
  219. BCDNegate(result);
  220. exp := (not(b[1]) and $7f)-65;
  221. if b[size]=102 then // last byte doesn't count if = 102
  222. size:=size-1;
  223. for i := 0 to size-2 do
  224. begin
  225. bb := 101-b[i+2];
  226. nibbles[i*2]:=bb div 10;
  227. nibbles[i*2+1]:=(bb mod 10);
  228. end;
  229. end;
  230. nibbles[(size-1)*2]:=0;
  231. result.Precision:=(size-1)*2;
  232. scale:=result.Precision-(exp*2+2);
  233. if scale>=0 then
  234. begin
  235. if (scale>result.Precision) then // need to add leading 0s
  236. begin
  237. for i:=0 to (scale-result.Precision+1) div 2 do
  238. result.Fraction[i]:=0;
  239. i:=scale-result.Precision;
  240. result.Precision:=scale;
  241. end
  242. else
  243. i:=0;
  244. j:=i;
  245. if (i=0) and (nibbles[0]=0) then // get rid of leading zero received from oci
  246. begin
  247. result.Precision:=result.Precision-1;
  248. j:=-1;
  249. end;
  250. while i<=result.Precision do // copy nibbles
  251. begin
  252. if i mod 2 =0 then
  253. result.Fraction[i div 2]:=nibbles[i-j] shl 4
  254. else
  255. result.Fraction[i div 2]:=result.Fraction[i div 2] or nibbles[i-j];
  256. i:=i+1;
  257. end;
  258. result.SignSpecialPlaces:=result.SignSpecialPlaces or scale;
  259. end
  260. else
  261. begin // add trailing zeroes, increase precision to take them into account
  262. i:=0;
  263. while i<=result.Precision do // copy nibbles
  264. begin
  265. if i mod 2 =0 then
  266. result.Fraction[i div 2]:=nibbles[i] shl 4
  267. else
  268. result.Fraction[i div 2]:=result.Fraction[i div 2] or nibbles[i];
  269. i:=i+1;
  270. end;
  271. result.Precision:=result.Precision-scale;
  272. for i := size -1 to High(result.Fraction) do
  273. result.Fraction[i] := 0;
  274. end;
  275. end;
  276. end;
  277. // TOracleConnection
  278. procedure TOracleConnection.HandleError;
  279. var errcode : sb4;
  280. buf : array[0..1023] of char;
  281. E : EOraDatabaseError;
  282. begin
  283. OCIErrorGet(FOciError,1,nil,errcode,@buf[0],1024,OCI_HTYPE_ERROR);
  284. if (Self.Name <> '') then
  285. E := EOraDatabaseError.CreateFmt('%s : %s',[Self.Name,pchar(buf)])
  286. else
  287. E := EOraDatabaseError.Create(pchar(buf));
  288. E.ORAErrorCode := errcode;
  289. Raise E;
  290. end;
  291. procedure TOracleConnection.GetParameters(cursor: TSQLCursor; AParams: TParams
  292. );
  293. var SQLVarNr : integer;
  294. i : integer;
  295. f : double;
  296. year,month,day : word;
  297. db : array[0..4] of byte;
  298. pb : pbyte;
  299. s : string;
  300. begin
  301. with cursor as TOracleCursor do for SQLVarNr := 0 to High(ParamBuffers) do
  302. with AParams[SQLVarNr] do
  303. if ParamType=ptOutput then
  304. begin
  305. if parambuffers[SQLVarNr].ind = -1 then
  306. Value:=null;
  307. case DataType of
  308. ftInteger : begin
  309. move(parambuffers[SQLVarNr].buffer^,i,sizeof(integer));
  310. asInteger := i;
  311. end;
  312. ftFloat : begin
  313. move(parambuffers[SQLVarNr].buffer^,f,sizeof(double));
  314. asFloat := f;
  315. end;
  316. ftString : begin
  317. SetLength(s,parambuffers[SQLVarNr].Len);
  318. move(parambuffers[SQLVarNr].buffer^,s[1],length(s)+1);
  319. asString:=s;
  320. end;
  321. ftDate, ftDateTime: begin
  322. pb := parambuffers[SQLVarNr].buffer;
  323. year:=(pb[0]-100)*100+pb[1]-100;
  324. month:=pb[2];
  325. day:=pb[3];
  326. asDateTime:=EncodeDate(year,month,day);
  327. end;
  328. ftFMTBcd : begin
  329. AsFMTBCD:=Nvu2FmtBCE(parambuffers[SQLVarNr].buffer);
  330. end;
  331. end;
  332. end;
  333. end;
  334. procedure TOracleConnection.DoInternalConnect;
  335. var
  336. ConnectString : string;
  337. TempServiceContext : POCISvcCtx;
  338. begin
  339. {$IfDef LinkDynamically}
  340. InitialiseOCI;
  341. {$EndIf}
  342. inherited DoInternalConnect;
  343. //todo: get rid of FUserMem, as it isn't used
  344. FUserMem := nil;
  345. // Create environment handle
  346. if OCIEnvCreate(FOciEnvironment,oci_default,nil,nil,nil,nil,0,FUserMem) <> OCI_SUCCESS then
  347. DatabaseError(SErrEnvCreateFailed,self);
  348. // Create error handle
  349. if OciHandleAlloc(FOciEnvironment,FOciError,OCI_HTYPE_ERROR,0,FUserMem) <> OCI_SUCCESS then
  350. DatabaseError(SErrHandleAllocFailed,self);
  351. // Create Server handle
  352. if OciHandleAlloc(FOciEnvironment,FOciServer,OCI_HTYPE_SERVER,0,FUserMem) <> OCI_SUCCESS then
  353. DatabaseError(SErrHandleAllocFailed,self);
  354. // Initialize Server handle
  355. if hostname='' then connectstring := databasename
  356. else connectstring := '//'+hostname+'/'+databasename;
  357. if OCIServerAttach(FOciServer,FOciError,@(ConnectString[1]),Length(ConnectString),OCI_DEFAULT) <> OCI_SUCCESS then
  358. HandleError();
  359. // Create temporary service-context handle for user authentication
  360. if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
  361. DatabaseError(SErrHandleAllocFailed,self);
  362. // Create user-session handle
  363. if OciHandleAlloc(FOciEnvironment,FOciUserSession,OCI_HTYPE_SESSION,0,FUserMem) <> OCI_SUCCESS then
  364. DatabaseError(SErrHandleAllocFailed,self);
  365. // Set the server-handle in the service-context handle
  366. if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
  367. HandleError();
  368. // Set username and password in the user-session handle
  369. if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.UserName[1]),Length(Self.UserName),OCI_ATTR_USERNAME,FOciError) <> OCI_SUCCESS then
  370. HandleError();
  371. if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.Password[1]),Length(Self.Password),OCI_ATTR_PASSWORD,FOciError) <> OCI_SUCCESS then
  372. HandleError();
  373. // Authenticate
  374. if OCISessionBegin(TempServiceContext,FOciError,FOcIUserSession,OCI_CRED_RDBMS,OCI_DEFAULT) <> OCI_SUCCESS then
  375. HandleError();
  376. // Free temporary service-context handle
  377. OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
  378. end;
  379. procedure TOracleConnection.DoInternalDisconnect;
  380. var
  381. TempServiceContext : POCISvcCtx;
  382. begin
  383. inherited DoInternalDisconnect;
  384. // Create temporary service-context handle for user-disconnect
  385. if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
  386. DatabaseError(SErrHandleAllocFailed,self);
  387. // Set the server handle in the service-context handle
  388. if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
  389. HandleError();
  390. // Set the user session handle in the service-context handle
  391. if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then
  392. HandleError();
  393. // Disconnect uses-session handle
  394. if OCISessionEnd(TempServiceContext,FOciError,FOcIUserSession,OCI_DEFAULT) <> OCI_SUCCESS then
  395. HandleError();
  396. // Free user-session handle
  397. OCIHandleFree(FOciUserSession,OCI_HTYPE_SESSION);
  398. // Free temporary service-context handle
  399. OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
  400. // Disconnect server handle
  401. if OCIServerDetach(FOciServer,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
  402. HandleError();
  403. // Free connection handles
  404. OCIHandleFree(FOciServer,OCI_HTYPE_SERVER);
  405. OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
  406. OCIHandleFree(FOciEnvironment,OCI_HTYPE_ENV);
  407. {$IfDef LinkDynamically}
  408. ReleaseOCI;
  409. {$EndIf}
  410. end;
  411. function TOracleConnection.AllocateCursorHandle: TSQLCursor;
  412. var Cursor : TOracleCursor;
  413. begin
  414. Cursor:=TOracleCursor.Create;
  415. Result := cursor;
  416. end;
  417. procedure TOracleConnection.DeAllocateCursorHandle(var cursor: TSQLCursor);
  418. var counter : word;
  419. begin
  420. with cursor as TOracleCursor do
  421. begin
  422. if Length(FieldBuffers) > 0 then
  423. for counter := 0 to high(FieldBuffers) do freemem(FieldBuffers[counter].buffer);
  424. if Length(ParamBuffers) > 0 then
  425. for counter := 0 to high(ParamBuffers) do freemem(ParamBuffers[counter].buffer);
  426. end;
  427. FreeAndNil(cursor);
  428. end;
  429. function TOracleConnection.AllocateTransactionHandle: TSQLHandle;
  430. var
  431. locRes : TOracleTrans;
  432. begin
  433. locRes := TOracleTrans.Create();
  434. try
  435. // Allocate service-context handle
  436. if OciHandleAlloc(FOciEnvironment,locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
  437. DatabaseError(SErrHandleAllocFailed,self);
  438. // Set the server-handle in the service-context handle
  439. if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
  440. HandleError();
  441. // Set the user-session handle in the service-context handle
  442. if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then
  443. HandleError();
  444. // Allocate transaction handle
  445. if OciHandleAlloc(FOciEnvironment,locRes.FOciTrans,OCI_HTYPE_TRANS,0,FUserMem) <> OCI_SUCCESS then
  446. DatabaseError(SErrHandleAllocFailed,self);
  447. // Set the transaction handle in the service-context handle
  448. if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,locRes.FOciTrans,0,OCI_ATTR_TRANS,FOciError) <> OCI_SUCCESS then
  449. HandleError();
  450. except
  451. locRes.Free();
  452. raise;
  453. end;
  454. Result := locRes;
  455. end;
  456. procedure TOracleConnection.PrepareStatement(cursor: TSQLCursor;
  457. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  458. var counter : integer;
  459. FOcibind : POCIDefine;
  460. OFieldType : ub2;
  461. OFieldSize : sb4;
  462. stmttype : ub2;
  463. begin
  464. with cursor as TOracleCursor do
  465. begin
  466. if OCIStmtPrepare2(TOracleTrans(ATransaction.Handle).FOciSvcCtx,FOciStmt,FOciError,@buf[1],length(buf),nil,0,OCI_NTV_SYNTAX,OCI_DEFAULT) = OCI_ERROR then
  467. HandleError;
  468. // get statement type
  469. if OCIAttrGet(FOciStmt,OCI_HTYPE_STMT,@stmttype,nil,OCI_ATTR_STMT_TYPE,FOciError) = OCI_ERROR then
  470. HandleError;
  471. case stmttype of
  472. OCI_STMT_SELECT:FStatementType := stSelect;
  473. OCI_STMT_UPDATE:FStatementType := stUpdate;
  474. OCI_STMT_DELETE:FStatementType := stDelete;
  475. OCI_STMT_INSERT:FStatementType := stInsert;
  476. OCI_STMT_CREATE,
  477. OCI_STMT_DROP,
  478. OCI_STMT_DECLARE,
  479. OCI_STMT_ALTER:FStatementType := stDDL;
  480. else
  481. FStatementType := stUnknown;
  482. end;
  483. if FStatementType in [stUpdate,stDelete,stInsert,stDDL] then
  484. FSelectable:=false;
  485. if assigned(AParams) then
  486. begin
  487. setlength(ParamBuffers,AParams.Count);
  488. for counter := 0 to AParams.Count-1 do
  489. begin
  490. case AParams[counter].DataType of
  491. ftSmallInt, ftInteger :
  492. begin OFieldType := SQLT_INT; OFieldSize := sizeof(integer); end;
  493. ftLargeInt :
  494. begin OFieldType := SQLT_INT; OFieldSize := sizeof(int64); end;
  495. ftFloat :
  496. begin OFieldType := SQLT_FLT; OFieldSize := sizeof(double); end;
  497. ftDate, ftDateTime :
  498. begin OFieldType := SQLT_DAT; OFieldSize := 7; end;
  499. ftFixedChar, ftString :
  500. begin OFieldType := SQLT_STR; OFieldSize := 4000; end;
  501. ftFMTBcd, ftBCD :
  502. begin OFieldType := SQLT_VNU; OFieldSize := 22; end;
  503. else
  504. DatabaseErrorFmt(SUnsupportedParameter,[Fieldtypenames[AParams[counter].DataType]],self);
  505. end;
  506. parambuffers[counter].buffer := getmem(OFieldSize);
  507. parambuffers[counter].Len := OFieldSize;
  508. parambuffers[counter].Size := OFieldSize;
  509. FOciBind := nil;
  510. if AParams[counter].ParamType=ptInput then
  511. begin
  512. if OCIBindByName(FOciStmt,FOcibind,FOciError,pchar(AParams[counter].Name),length(AParams[counter].Name),ParamBuffers[counter].buffer,OFieldSize,OFieldType,@ParamBuffers[counter].ind,nil,nil,0,nil,OCI_DEFAULT )= OCI_ERROR then
  513. HandleError;
  514. end
  515. else if AParams[counter].ParamType=ptOutput then
  516. begin
  517. if OCIBindByName(FOciStmt,FOcibind,FOciError,pchar(AParams[counter].Name),length(AParams[counter].Name),nil,OFieldSize,OFieldType,nil,nil,nil,0,nil,OCI_DATA_AT_EXEC )= OCI_ERROR then
  518. HandleError;
  519. if OCIBindDynamic(FOcibind, FOciError, nil, @cbf_no_data, @parambuffers[counter], @cbf_get_data) <> OCI_SUCCESS then
  520. HandleError;
  521. end;
  522. end;
  523. end;
  524. FPrepared := True;
  525. end;
  526. end;
  527. procedure TOracleConnection.SetParameters(cursor : TSQLCursor;AParams : TParams);
  528. var SQLVarNr : integer;
  529. i : integer;
  530. f : double;
  531. year, month, day, hour, minute, second, millisecond : word;
  532. db : array[0..4] of byte;
  533. pb : pbyte;
  534. s : string;
  535. begin
  536. with cursor as TOracleCursor do for SQLVarNr := 0 to High(ParamBuffers) do with AParams[SQLVarNr] do
  537. if ParamType=ptInput then
  538. begin
  539. if IsNull then parambuffers[SQLVarNr].ind := -1 else
  540. parambuffers[SQLVarNr].ind := 0;
  541. case DataType of
  542. ftSmallInt,
  543. ftInteger : begin
  544. i := asInteger;
  545. move(i,parambuffers[SQLVarNr].buffer^,sizeof(integer));
  546. end;
  547. ftLargeInt : PInt64(parambuffers[SQLVarNr].buffer)^ := AsLargeInt;
  548. ftFloat : begin
  549. f := asFloat;
  550. move(f,parambuffers[SQLVarNr].buffer^,sizeof(double));
  551. end;
  552. ftString,
  553. ftFixedChar : begin
  554. s := asString+#0;
  555. move(s[1],parambuffers[SQLVarNr].buffer^,length(s)+1);
  556. end;
  557. ftDate, ftDateTime: begin
  558. DecodeDate(asDateTime,year,month,day);
  559. DecodeTime(asDateTime,hour,minute,second,millisecond);
  560. pb := parambuffers[SQLVarNr].buffer;
  561. pb[0] := (year div 100)+100;
  562. pb[1] := (year mod 100)+100;
  563. pb[2] := month;
  564. pb[3] := day;
  565. pb[4] := hour+1;
  566. pb[5] := minute+1;
  567. pb[6] := second+1;
  568. end;
  569. ftFmtBCD,ftBCD : begin
  570. FmtBCD2Nvu(asFmtBCD,parambuffers[SQLVarNr].buffer);
  571. end;
  572. else
  573. DatabaseErrorFmt(SUnsupportedParameter,[DataType],self);
  574. end;
  575. end;
  576. end;
  577. procedure TOracleConnection.UnPrepareStatement(cursor: TSQLCursor);
  578. begin
  579. if OCIStmtRelease(TOracleCursor(cursor).FOciStmt,FOciError,nil,0,OCI_DEFAULT)<> OCI_SUCCESS then
  580. HandleError();
  581. cursor.FPrepared:=False;
  582. end;
  583. procedure TOracleConnection.InternalStartDBTransaction(trans : TOracleTrans);
  584. begin
  585. if OCITransStart(trans.FOciSvcCtx,FOciError,DefaultTimeOut,trans.FOciFlags) <> OCI_SUCCESS then
  586. HandleError();
  587. end;
  588. function TOracleConnection.GetTransactionHandle(trans: TSQLHandle): pointer;
  589. begin
  590. Result := trans;
  591. end;
  592. function TOracleConnection.StartDBTransaction(trans: TSQLHandle; AParams: string): boolean;
  593. var
  594. x_flags : ub4;
  595. i : Integer;
  596. s : string;
  597. locTrans : TOracleTrans;
  598. begin
  599. locTrans := TOracleTrans(trans);
  600. if ( Length(AParams) = 0 ) then begin
  601. x_flags := OCI_TRANS_NEW or OCI_TRANS_READWRITE;
  602. end else begin
  603. x_flags := OCI_DEFAULT;
  604. i := 1;
  605. s := ExtractSubStr(AParams,i,StdWordDelims);
  606. while ( s <> '' ) do begin
  607. if ( s = 'readonly' ) then
  608. x_flags := x_flags and OCI_TRANS_READONLY
  609. else if ( s = 'serializable' ) then
  610. x_flags := x_flags and OCI_TRANS_SERIALIZABLE
  611. else if ( s = 'readwrite' ) then
  612. x_flags := x_flags and OCI_TRANS_READWRITE;
  613. s := ExtractSubStr(AParams,i,StdWordDelims);
  614. end;
  615. x_flags := x_flags and OCI_TRANS_NEW;
  616. end;
  617. locTrans.FOciFlags := x_flags;
  618. InternalStartDBTransaction(locTrans);
  619. Result := True;
  620. end;
  621. function TOracleConnection.Commit(trans: TSQLHandle): boolean;
  622. begin
  623. if OCITransCommit(TOracleTrans(trans).FOciSvcCtx,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
  624. HandleError();
  625. Result := True;
  626. end;
  627. function TOracleConnection.Rollback(trans: TSQLHandle): boolean;
  628. begin
  629. if OCITransRollback(TOracleTrans(trans).FOciSvcCtx,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
  630. HandleError();
  631. Result := True;
  632. end;
  633. procedure TOracleConnection.CommitRetaining(trans: TSQLHandle);
  634. begin
  635. Commit(trans);
  636. InternalStartDBTransaction(TOracleTrans(trans));
  637. end;
  638. procedure TOracleConnection.RollbackRetaining(trans: TSQLHandle);
  639. begin
  640. Rollback(trans);
  641. InternalStartDBTransaction(TOracleTrans(trans));
  642. end;
  643. procedure TOracleConnection.Execute(cursor: TSQLCursor; ATransaction: TSQLTransaction; AParams: TParams);
  644. begin
  645. if Assigned(AParams) and (AParams.Count > 0) then SetParameters(cursor, AParams);
  646. if cursor.FStatementType = stSelect then
  647. begin
  648. if OCIStmtExecute(TOracleTrans(ATransaction.Handle).FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,0,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
  649. HandleError;
  650. end
  651. else
  652. begin
  653. if OCIStmtExecute(TOracleTrans(ATransaction.Handle).FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,1,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
  654. HandleError;
  655. if Assigned(AParams) and (AParams.Count > 0) then GetParameters(cursor, AParams);
  656. end;
  657. end;
  658. function TOracleConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
  659. var rowcount: ub4;
  660. begin
  661. if Assigned(cursor) and (OCIAttrGet((cursor as TOracleCursor).FOciStmt, OCI_HTYPE_STMT, @rowcount, nil, OCI_ATTR_ROW_COUNT, FOciError) = OCI_SUCCESS) then
  662. Result:=rowcount
  663. else
  664. Result:=inherited RowsAffected(cursor);
  665. end;
  666. procedure TOracleConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TFieldDefs);
  667. var Param : POCIParam;
  668. counter : ub4;
  669. FieldType : TFieldType;
  670. FieldName : string;
  671. FieldSize : cardinal;
  672. OFieldType : ub2;
  673. OFieldName : Pchar;
  674. OFieldSize : ub4;
  675. OFNameLength : ub4;
  676. NumCols : ub4;
  677. FOciDefine : POCIDefine;
  678. OPrecision : sb2;
  679. OScale : sb1;
  680. begin
  681. Param := nil;
  682. with cursor as TOracleCursor do
  683. begin
  684. if OCIAttrGet(FOciStmt,OCI_HTYPE_STMT,@numcols,nil,OCI_ATTR_PARAM_COUNT,FOciError) = OCI_ERROR then
  685. HandleError;
  686. // Note: needs to be cleared then allocated in one go.
  687. Setlength(FieldBuffers,numcols);
  688. for counter := 1 to numcols do
  689. begin
  690. // Clear OFieldSize. Oracle 9i, 10g doc says *ub4 but some clients use *ub2 leaving
  691. // high 16 bit untouched resulting in huge values and ORA-01062
  692. // WARNING: this is not working in big endian systems !!!!
  693. // To be tested if BE systems have this *ub2<->*ub4 problem
  694. OFieldSize:=0;
  695. if OCIParamGet(FOciStmt,OCI_HTYPE_STMT,FOciError,Param,counter) = OCI_ERROR then
  696. HandleError;
  697. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldType,nil,OCI_ATTR_DATA_TYPE,FOciError) = OCI_ERROR then
  698. HandleError;
  699. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldSize,nil,OCI_ATTR_DATA_SIZE,FOciError) = OCI_ERROR then
  700. HandleError;
  701. FieldSize := 0;
  702. case OFieldType of
  703. OCI_TYPECODE_NUMBER : begin
  704. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oprecision,nil,OCI_ATTR_PRECISION,FOciError) = OCI_ERROR then
  705. HandleError;
  706. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oscale,nil,OCI_ATTR_SCALE,FOciError) = OCI_ERROR then
  707. HandleError;
  708. if (Oscale = 0) and (Oprecision < 10) then
  709. begin
  710. if Oprecision=0 then //Number(0,0) = number(32,4)
  711. begin
  712. FieldType := ftFMTBCD;
  713. FieldSize := 4;
  714. OFieldType := SQLT_VNU;
  715. OFieldSize:= 22;
  716. end
  717. else if Oprecision < 5 then
  718. begin
  719. FieldType := ftSmallint;
  720. OFieldType := SQLT_INT;
  721. OFieldSize := sizeof(smallint);
  722. end
  723. else
  724. begin
  725. FieldType := ftInteger;
  726. OFieldType := SQLT_INT;
  727. OFieldSize:= sizeof(integer);
  728. end;
  729. end
  730. else if (Oscale = -127) {and (OPrecision=0)} then
  731. begin
  732. FieldType := ftFloat;
  733. OFieldType := SQLT_FLT;
  734. OFieldSize:=sizeof(double);
  735. end
  736. else if (Oscale >=0) and (Oscale <=4) and (OPrecision<=12) then
  737. begin
  738. FieldType := ftBCD;
  739. FieldSize := oscale;
  740. OFieldType := SQLT_VNU;
  741. OFieldSize:= 22;
  742. end
  743. else if (OPrecision-Oscale<64) and (Oscale < 64) then // limited to 63 digits before or after decimal point
  744. begin
  745. FieldType := ftFMTBCD;
  746. FieldSize := oscale;
  747. OFieldType := SQLT_VNU;
  748. OFieldSize:= 22;
  749. end
  750. else // approximation with double, best we can do
  751. begin
  752. FieldType := ftFloat;
  753. OFieldType := SQLT_FLT;
  754. OFieldSize:=sizeof(double);
  755. end;
  756. end;
  757. OCI_TYPECODE_CHAR,
  758. OCI_TYPECODE_VARCHAR,
  759. OCI_TYPECODE_VARCHAR2 : begin
  760. FieldType := ftString;
  761. FieldSize := OFieldSize;
  762. inc(OFieldSize);
  763. OFieldType:=SQLT_STR;
  764. end;
  765. OCI_TYPECODE_DATE : FieldType := ftDate;
  766. OCI_TYPECODE_TIMESTAMP,
  767. OCI_TYPECODE_TIMESTAMP_LTZ,
  768. OCI_TYPECODE_TIMESTAMP_TZ :
  769. begin
  770. FieldType := ftDateTime;
  771. OFieldType := SQLT_ODT;
  772. end;
  773. OCI_TYPECODE_BFLOAT,
  774. OCI_TYPECODE_BDOUBLE : begin
  775. FieldType := ftFloat;
  776. OFieldType := SQLT_BDOUBLE;
  777. OFieldSize := sizeof(double);
  778. end
  779. else
  780. FieldType := ftUnknown;
  781. end;
  782. FieldBuffers[counter-1].buffer := getmem(OFieldSize);
  783. if FieldType <> ftUnknown then
  784. begin
  785. FOciDefine := nil;
  786. if OciDefineByPos(FOciStmt,FOciDefine,FOciError,counter,fieldbuffers[counter-1].buffer,OFieldSize,OFieldType,@(fieldbuffers[counter-1].ind),nil,nil,OCI_DEFAULT) = OCI_ERROR then
  787. HandleError;
  788. end;
  789. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldName,@OFNameLength,OCI_ATTR_NAME,FOciError) <> OCI_SUCCESS then
  790. HandleError;
  791. setlength(Fieldname,OFNameLength);
  792. move(OFieldName^,Fieldname[1],OFNameLength);
  793. FieldDefs.Add(FieldDefs.MakeNameUnique(FieldName), FieldType, FieldSize, False, counter);
  794. end;
  795. end;
  796. end;
  797. function TOracleConnection.Fetch(cursor: TSQLCursor): boolean;
  798. begin
  799. case OCIStmtFetch2((cursor as TOracleCursor).FOciStmt,FOciError,1,OCI_FETCH_NEXT,1,OCI_DEFAULT) of
  800. OCI_ERROR : begin
  801. Result := False;
  802. HandleError;
  803. end;
  804. OCI_NO_DATA : Result := False;
  805. OCI_SUCCESS : Result := True;
  806. OCI_SUCCESS_WITH_INFO : Begin
  807. Result := True;
  808. HandleError;
  809. end;
  810. end; {case}
  811. end;
  812. function TOracleConnection.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef; buffer: pointer; out CreateBlob : boolean): boolean;
  813. var dt : TDateTime;
  814. b : pbyte;
  815. size,i : byte;
  816. exp : shortint;
  817. cur : Currency;
  818. odt : POCIdateTime;
  819. begin
  820. CreateBlob := False;
  821. with cursor as TOracleCursor do if fieldbuffers[FieldDef.FieldNo-1].ind = -1 then
  822. Result := False
  823. else
  824. begin
  825. result := True;
  826. case FieldDef.DataType of
  827. ftString : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,FieldDef.Size);
  828. ftBCD : begin
  829. b := fieldbuffers[FieldDef.FieldNo-1].buffer;
  830. size := b[0];
  831. cur := 0;
  832. if (b[1] and $80)=$80 then // then the number is positive
  833. begin
  834. exp := (b[1] and $7f)-65;
  835. for i := 2 to size do
  836. cur := cur + (b[i]-1) * intpower(100,-(i-2)+exp);
  837. end
  838. else
  839. begin
  840. exp := (not(b[1]) and $7f)-65;
  841. for i := 2 to size-1 do
  842. cur := cur + (101-b[i]) * intpower(100,-(i-2)+exp);
  843. cur := -cur;
  844. end;
  845. move(cur,buffer^,SizeOf(Currency));
  846. end;
  847. ftFMTBCD : begin
  848. pBCD(buffer)^:= Nvu2FmtBCE(fieldbuffers[FieldDef.FieldNo-1].buffer);
  849. end;
  850. ftFloat : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(double));
  851. ftSmallInt : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(smallint));
  852. ftInteger : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(integer));
  853. ftDate : begin
  854. b := fieldbuffers[FieldDef.FieldNo-1].buffer;
  855. dt := ComposeDateTime(EncodeDate((b[0]-100)*100+(b[1]-100),b[2],b[3]), EncodeTime(b[4]-1, b[5]-1, b[6]-1, 0));
  856. move(dt,buffer^,sizeof(dt));
  857. end;
  858. ftDateTime : begin
  859. odt := fieldbuffers[FieldDef.FieldNo-1].buffer;
  860. dt := ComposeDateTime(EncodeDate(odt^.year,odt^.month,odt^.day), EncodeTime(odt^.hour,odt^.min,odt^.sec,0));
  861. move(dt,buffer^,sizeof(dt));
  862. end;
  863. else
  864. Result := False;
  865. end;
  866. end;
  867. end;
  868. {procedure TOracleConnection.LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  869. begin
  870. end;}
  871. procedure TOracleConnection.FreeFldBuffers(cursor: TSQLCursor);
  872. begin
  873. // inherited FreeFldBuffers(cursor);
  874. end;
  875. procedure TOracleConnection.UpdateIndexDefs(IndexDefs: TIndexDefs;
  876. TableName: string);
  877. var qry : TSQLQuery;
  878. begin
  879. if not assigned(Transaction) then
  880. DatabaseError(SErrConnTransactionnSet);
  881. qry := tsqlquery.Create(nil);
  882. qry.transaction := Transaction;
  883. qry.database := Self;
  884. with qry do
  885. begin
  886. ReadOnly := True;
  887. sql.clear;
  888. sql.add('SELECT '+
  889. 'i.INDEX_NAME, '+
  890. 'c.COLUMN_NAME, '+
  891. 'p.CONSTRAINT_TYPE '+
  892. 'FROM ALL_INDEXES i, ALL_IND_COLUMNS c,ALL_CONSTRAINTS p '+
  893. 'WHERE '+
  894. 'i.OWNER=c.INDEX_OWNER AND '+
  895. 'i.INDEX_NAME=c.INDEX_NAME AND '+
  896. 'p.INDEX_NAME(+)=i.INDEX_NAME AND '+
  897. 'Upper(c.TABLE_NAME) = ''' + UpperCase(TableName) +''' '+
  898. 'ORDER by i.INDEX_NAME,c.COLUMN_POSITION');
  899. open;
  900. end;
  901. while not qry.eof do with IndexDefs.AddIndexDef do
  902. begin
  903. Name := trim(qry.fields[0].asstring);
  904. Fields := trim(qry.Fields[1].asstring);
  905. If UpperCase(qry.fields[2].asString)='P' then options := options + [ixPrimary];
  906. If UpperCase(qry.fields[2].asString)='U' then options := options + [ixUnique];
  907. qry.next;
  908. while (name = qry.fields[0].asstring) and (not qry.eof) do
  909. begin
  910. Fields := Fields + ';' + trim(qry.Fields[2].asstring);
  911. qry.next;
  912. end;
  913. end;
  914. qry.close;
  915. qry.free;
  916. end;
  917. function TOracleConnection.GetSchemaInfoSQL(SchemaType: TSchemaType;
  918. SchemaObjectName, SchemaPattern: string): string;
  919. var s : string;
  920. begin
  921. case SchemaType of
  922. stTables : s := 'SELECT '+
  923. '''' + DatabaseName + ''' as catalog_name, '+
  924. 'sys_context( ''userenv'', ''current_schema'' ) as schema_name, '+
  925. 'TABLE_NAME '+
  926. 'FROM USER_CATALOG ' +
  927. 'WHERE '+
  928. 'TABLE_TYPE<>''SEQUENCE'' '+
  929. 'ORDER BY TABLE_NAME';
  930. stSysTables : s := 'SELECT '+
  931. '''' + DatabaseName + ''' as catalog_name, '+
  932. 'OWNER as schema_name, '+
  933. 'TABLE_NAME '+
  934. 'FROM ALL_CATALOG ' +
  935. 'WHERE '+
  936. 'TABLE_TYPE<>''SEQUENCE'' '+
  937. 'ORDER BY TABLE_NAME';
  938. stColumns : s := 'SELECT '+
  939. 'COLUMN_NAME, '+
  940. 'DATA_TYPE as column_datatype, '+
  941. 'CHARACTER_SET_NAME, '+
  942. 'NULLABLE as column_nullable, '+
  943. 'DATA_LENGTH as column_length, '+
  944. 'DATA_PRECISION as column_precision, '+
  945. 'DATA_SCALE as column_scale '+
  946. {DATA_DEFAULT is type LONG; no support for that in
  947. oracleconnection so removed this from query }
  948. 'FROM ALL_TAB_COLUMNS '+
  949. 'WHERE Upper(TABLE_NAME) = '''+UpperCase(SchemaObjectName)+''' '+
  950. 'ORDER BY COLUMN_NAME';
  951. // Columns of tables, views and clusters accessible to user; hidden columns are filtered out.
  952. stProcedures : s := 'SELECT '+
  953. 'case when PROCEDURE_NAME is null then OBJECT_NAME ELSE OBJECT_NAME || ''.'' || PROCEDURE_NAME end AS procedure_name '+
  954. 'FROM USER_PROCEDURES ';
  955. else
  956. DatabaseError(SMetadataUnavailable)
  957. end; {case}
  958. result := s;
  959. end;
  960. constructor TOracleConnection.Create(AOwner: TComponent);
  961. begin
  962. inherited Create(AOwner);
  963. FConnOptions := FConnOptions + [sqEscapeRepeat];
  964. FUserMem := nil;
  965. end;
  966. { TOracleConnectionDef }
  967. class function TOracleConnectionDef.TypeName: String;
  968. begin
  969. Result:='Oracle';
  970. end;
  971. class function TOracleConnectionDef.ConnectionClass: TSQLConnectionClass;
  972. begin
  973. Result:=TOracleConnection;
  974. end;
  975. class function TOracleConnectionDef.Description: String;
  976. begin
  977. Result:='Connect to an Oracle database directly via the client library';
  978. end;
  979. class function TOracleConnectionDef.DefaultLibraryName: String;
  980. begin
  981. {$IfDef LinkDynamically}
  982. Result:=ocilib;
  983. {$else}
  984. Result:='';
  985. {$endif}
  986. end;
  987. class function TOracleConnectionDef.LoadFunction: TLibraryLoadFunction;
  988. begin
  989. {$IfDef LinkDynamically}
  990. Result:=@InitialiseOCI;
  991. {$else}
  992. Result:=Nil;
  993. {$endif}
  994. end;
  995. class function TOracleConnectionDef.UnLoadFunction: TLibraryUnLoadFunction;
  996. begin
  997. {$IfDef LinkDynamically}
  998. Result:=@ReleaseOCI;
  999. {$else}
  1000. Result:=Nil;
  1001. {$endif}
  1002. end;
  1003. class function TOracleConnectionDef.LoadedLibraryName: string;
  1004. begin
  1005. {$IfDef LinkDynamically}
  1006. Result:=OCILoadedLibrary;
  1007. {$else}
  1008. Result:='';
  1009. {$endif}
  1010. end;
  1011. { TOracleTrans }
  1012. destructor TOracleTrans.Destroy();
  1013. begin
  1014. OCIHandleFree(FOciTrans,OCI_HTYPE_TRANS);
  1015. OCIHandleFree(FOciSvcCtx,OCI_HTYPE_SVCCTX);
  1016. inherited Destroy();
  1017. end;
  1018. initialization
  1019. RegisterConnection(TOracleConnectionDef);
  1020. finalization
  1021. UnRegisterConnection(TOracleConnectionDef);
  1022. end.