2
0

oracleconnection.pp 42 KB

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