oracleconnection.pp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. unit oracleconnection;
  2. //
  3. // For usage of "returning" like clauses see mantis #18133
  4. //
  5. {$mode objfpc}{$H+}
  6. {$Define LinkDynamically}
  7. interface
  8. uses
  9. Classes, SysUtils, sqldb,db,dbconst,
  10. {$IfDef LinkDynamically}
  11. ocidyn,
  12. {$ELSE}
  13. oci,
  14. {$ENDIF}
  15. oratypes;
  16. const
  17. DefaultTimeOut = 60;
  18. type
  19. EOraDatabaseError = class(EDatabaseError)
  20. public
  21. ORAErrorCode : Longint;
  22. end;
  23. TOracleTrans = Class(TSQLHandle)
  24. protected
  25. FOciSvcCtx : POCISvcCtx;
  26. FOciTrans : POCITrans;
  27. FOciFlags : ub4;
  28. public
  29. destructor Destroy(); override;
  30. end;
  31. TOraFieldBuf = record
  32. Buffer : pointer;
  33. Ind : sb2;
  34. Len : ub4;
  35. Size : ub4;
  36. end;
  37. TOracleCursor = Class(TSQLCursor)
  38. protected
  39. FOciStmt : POCIStmt;
  40. FieldBuffers : array of TOraFieldBuf;
  41. ParamBuffers : array of TOraFieldBuf;
  42. end;
  43. { TOracleConnection }
  44. TOracleConnection = class (TSQLConnection)
  45. private
  46. FOciEnvironment : POciEnv;
  47. FOciError : POCIError;
  48. FOciServer : POCIServer;
  49. FOciUserSession : POCISession;
  50. FUserMem : pointer;
  51. procedure HandleError;
  52. procedure GetParameters(cursor : TSQLCursor;AParams : TParams);
  53. procedure SetParameters(cursor : TSQLCursor;AParams : TParams);
  54. protected
  55. // - Connect/disconnect
  56. procedure DoInternalConnect; override;
  57. procedure DoInternalDisconnect; override;
  58. // - Handle (de)allocation
  59. function AllocateCursorHandle:TSQLCursor; override;
  60. procedure DeAllocateCursorHandle(var cursor:TSQLCursor); override;
  61. function AllocateTransactionHandle:TSQLHandle; override;
  62. // - Statement handling
  63. procedure PrepareStatement(cursor:TSQLCursor; ATransaction:TSQLTransaction; buf:string; AParams:TParams); override;
  64. procedure UnPrepareStatement(cursor:TSQLCursor); override;
  65. // - Transaction handling
  66. procedure InternalStartDBTransaction(trans:TOracleTrans);
  67. function GetTransactionHandle(trans:TSQLHandle):pointer; override;
  68. function StartDBTransaction(trans:TSQLHandle; AParams:string):boolean; override;
  69. function Commit(trans:TSQLHandle):boolean; override;
  70. function Rollback(trans:TSQLHandle):boolean; override;
  71. procedure CommitRetaining(trans:TSQLHandle); override;
  72. procedure RollbackRetaining(trans:TSQLHandle); override;
  73. // - Statement execution
  74. procedure Execute(cursor:TSQLCursor; ATransaction:TSQLTransaction; AParams:TParams); override;
  75. function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
  76. // - Result retrieving
  77. procedure AddFieldDefs(cursor:TSQLCursor; FieldDefs:TFieldDefs); override;
  78. function Fetch(cursor:TSQLCursor):boolean; override;
  79. function LoadField(cursor:TSQLCursor; FieldDef:TFieldDef; buffer:pointer; out CreateBlob : boolean):boolean; override;
  80. // function CreateBlobStream(Field:TField; Mode:TBlobStreamMode):TStream; override;
  81. procedure FreeFldBuffers(cursor:TSQLCursor); override;
  82. public
  83. constructor Create(AOwner : TComponent); override;
  84. end;
  85. TOracleConnectionDef = Class(TConnectionDef)
  86. Class Function TypeName : String; override;
  87. Class Function ConnectionClass : TSQLConnectionClass; override;
  88. Class Function Description : String; override;
  89. end;
  90. implementation
  91. uses
  92. math, StrUtils;
  93. ResourceString
  94. SErrEnvCreateFailed = 'The creation of an Oracle environment failed.';
  95. SErrHandleAllocFailed = 'The allocation of the error handle failed.';
  96. SErrOracle = 'Oracle returned error %s:';
  97. //callback functions
  98. function cbf_no_data(ictxp:Pdvoid; bindp:POCIBind; iter:ub4; index:ub4; bufpp:PPdvoid;
  99. alenp:Pub4; piecep:Pub1; indp:PPdvoid):sb4;cdecl;
  100. begin
  101. bufpp^ := nil;
  102. alenp^ := 0;
  103. indp^ := nil;
  104. piecep^ := OCI_ONE_PIECE;
  105. result:=OCI_CONTINUE;
  106. end;
  107. function cbf_get_data(octxp:Pdvoid; bindp:POCIBind; iter:ub4; index:ub4; bufpp:PPdvoid;
  108. alenp:PPub4; piecep:Pub1; indp:PPdvoid; rcodep:PPub2):sb4;cdecl;
  109. begin
  110. //only 1 row can be stored. No support for multiple rows. When multiple rows, only last is kept.
  111. bufpp^:=TOraFieldBuf(octxp^).Buffer;
  112. indp^ := @TOraFieldBuf(octxp^).Ind;
  113. TOraFieldBuf(octxp^).Len:=TOraFieldBuf(octxp^).Size; //reset size to full buffer
  114. alenp^ := @TOraFieldBuf(octxp^).Len;
  115. rcodep^:=nil;
  116. piecep^ := OCI_ONE_PIECE;
  117. result:=OCI_CONTINUE;
  118. end;
  119. procedure TOracleConnection.HandleError;
  120. var errcode : sb4;
  121. buf : array[0..1023] of char;
  122. E : EOraDatabaseError;
  123. begin
  124. OCIErrorGet(FOciError,1,nil,errcode,@buf[0],1024,OCI_HTYPE_ERROR);
  125. if (Self.Name <> '') then
  126. E := EOraDatabaseError.CreateFmt('%s : %s',[Self.Name,pchar(buf)])
  127. else
  128. E := EOraDatabaseError.Create(pchar(buf));
  129. E.ORAErrorCode := errcode;
  130. Raise E;
  131. end;
  132. procedure TOracleConnection.GetParameters(cursor: TSQLCursor; AParams: TParams
  133. );
  134. var SQLVarNr : integer;
  135. i : integer;
  136. f : double;
  137. year,month,day : word;
  138. db : array[0..4] of byte;
  139. pb : pbyte;
  140. s : string;
  141. begin
  142. with cursor as TOracleCursor do for SQLVarNr := 0 to High(ParamBuffers) do
  143. with AParams[SQLVarNr] do
  144. if ParamType=ptOutput then
  145. begin
  146. if parambuffers[SQLVarNr].ind = -1 then
  147. Value:=null;
  148. case DataType of
  149. ftInteger : begin
  150. move(parambuffers[SQLVarNr].buffer^,i,sizeof(integer));
  151. asInteger := i;
  152. end;
  153. ftFloat : begin
  154. move(parambuffers[SQLVarNr].buffer^,f,sizeof(double));
  155. asFloat := f;
  156. end;
  157. ftString : begin
  158. SetLength(s,parambuffers[SQLVarNr].Len);
  159. move(parambuffers[SQLVarNr].buffer^,s[1],length(s)+1);
  160. asString:=s;
  161. end;
  162. ftDate, ftDateTime: begin
  163. pb := parambuffers[SQLVarNr].buffer;
  164. year:=(pb[0]-100)*100+pb[1]-100;
  165. month:=pb[2];
  166. day:=pb[3];
  167. asDateTime:=EncodeDate(year,month,day);
  168. end;
  169. end;
  170. end;
  171. end;
  172. procedure TOracleConnection.DoInternalConnect;
  173. var
  174. ConnectString : string;
  175. TempServiceContext : POCISvcCtx;
  176. begin
  177. {$IfDef LinkDynamically}
  178. InitialiseOCI;
  179. {$EndIf}
  180. inherited DoInternalConnect;
  181. //todo: get rid of FUserMem, as it isn't used
  182. FUserMem := nil;
  183. // Create environment handle
  184. if OCIEnvCreate(FOciEnvironment,oci_default,nil,nil,nil,nil,0,FUserMem) <> OCI_SUCCESS then
  185. DatabaseError(SErrEnvCreateFailed,self);
  186. // Create error handle
  187. if OciHandleAlloc(FOciEnvironment,FOciError,OCI_HTYPE_ERROR,0,FUserMem) <> OCI_SUCCESS then
  188. DatabaseError(SErrHandleAllocFailed,self);
  189. // Create Server handle
  190. if OciHandleAlloc(FOciEnvironment,FOciServer,OCI_HTYPE_SERVER,0,FUserMem) <> OCI_SUCCESS then
  191. DatabaseError(SErrHandleAllocFailed,self);
  192. // Initialize Server handle
  193. if hostname='' then connectstring := databasename
  194. else connectstring := '//'+hostname+'/'+databasename;
  195. if OCIServerAttach(FOciServer,FOciError,@(ConnectString[1]),Length(ConnectString),OCI_DEFAULT) <> OCI_SUCCESS then
  196. HandleError();
  197. // Create temporary service-context handle for user-authentication
  198. if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
  199. DatabaseError(SErrHandleAllocFailed,self);
  200. // Create user-session handle
  201. if OciHandleAlloc(FOciEnvironment,FOciUserSession,OCI_HTYPE_SESSION,0,FUserMem) <> OCI_SUCCESS then
  202. DatabaseError(SErrHandleAllocFailed,self);
  203. // Set the server-handle in the service-context handle
  204. if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
  205. HandleError();
  206. // Set username and password in the user-session handle
  207. if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.UserName[1]),Length(Self.UserName),OCI_ATTR_USERNAME,FOciError) <> OCI_SUCCESS then
  208. HandleError();
  209. if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.Password[1]),Length(Self.Password),OCI_ATTR_PASSWORD,FOciError) <> OCI_SUCCESS then
  210. HandleError();
  211. // Authenticate
  212. if OCISessionBegin(TempServiceContext,FOciError,FOcIUserSession,OCI_CRED_RDBMS,OCI_DEFAULT) <> OCI_SUCCESS then
  213. HandleError();
  214. // Free temporary service-context handle
  215. OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
  216. end;
  217. procedure TOracleConnection.DoInternalDisconnect;
  218. var
  219. TempServiceContext : POCISvcCtx;
  220. begin
  221. inherited DoInternalDisconnect;
  222. // Create temporary service-context handle for user-disconnect
  223. if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
  224. DatabaseError(SErrHandleAllocFailed,self);
  225. // Set the server handle in the service-context handle
  226. if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
  227. HandleError();
  228. // Set the user session handle in the service-context handle
  229. if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then
  230. HandleError();
  231. // Disconnect uses-session handle
  232. if OCISessionEnd(TempServiceContext,FOciError,FOcIUserSession,OCI_DEFAULT) <> OCI_SUCCESS then
  233. HandleError();
  234. // Free user-session handle
  235. OCIHandleFree(FOciUserSession,OCI_HTYPE_SESSION);
  236. // Free temporary service-context handle
  237. OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
  238. // Disconnect server handle
  239. if OCIServerDetach(FOciServer,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
  240. HandleError();
  241. // Free connection handles
  242. OCIHandleFree(FOciServer,OCI_HTYPE_SERVER);
  243. OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
  244. OCIHandleFree(FOciEnvironment,OCI_HTYPE_ENV);
  245. {$IfDef LinkDynamically}
  246. ReleaseOCI;
  247. {$EndIf}
  248. end;
  249. function TOracleConnection.AllocateCursorHandle: TSQLCursor;
  250. var Cursor : TOracleCursor;
  251. begin
  252. Cursor:=TOracleCursor.Create;
  253. Result := cursor;
  254. end;
  255. procedure TOracleConnection.DeAllocateCursorHandle(var cursor: TSQLCursor);
  256. var tel : word;
  257. begin
  258. with cursor as TOracleCursor do
  259. begin
  260. if Length(FieldBuffers) > 0 then
  261. for tel := 0 to high(FieldBuffers) do freemem(FieldBuffers[tel].buffer);
  262. end;
  263. FreeAndNil(cursor);
  264. end;
  265. function TOracleConnection.AllocateTransactionHandle: TSQLHandle;
  266. var
  267. locRes : TOracleTrans;
  268. begin
  269. locRes := TOracleTrans.Create();
  270. try
  271. // Allocate service-context handle
  272. if OciHandleAlloc(FOciEnvironment,locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
  273. DatabaseError(SErrHandleAllocFailed,self);
  274. // Set the server-handle in the service-context handle
  275. if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
  276. HandleError();
  277. // Set the user-session handle in the service-context handle
  278. if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then
  279. HandleError();
  280. // Allocate transaction handle
  281. if OciHandleAlloc(FOciEnvironment,locRes.FOciTrans,OCI_HTYPE_TRANS,0,FUserMem) <> OCI_SUCCESS then
  282. DatabaseError(SErrHandleAllocFailed,self);
  283. // Set the transaction handle in the service-context handle
  284. if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,locRes.FOciTrans,0,OCI_ATTR_TRANS,FOciError) <> OCI_SUCCESS then
  285. HandleError();
  286. except
  287. locRes.Free();
  288. raise;
  289. end;
  290. Result := locRes;
  291. end;
  292. procedure TOracleConnection.PrepareStatement(cursor: TSQLCursor;
  293. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  294. var tel : integer;
  295. FOcibind : POCIDefine;
  296. OFieldType : ub2;
  297. OFieldSize : sb4;
  298. begin
  299. with cursor as TOracleCursor do
  300. begin
  301. if OCIStmtPrepare2(TOracleTrans(ATransaction.Handle).FOciSvcCtx,FOciStmt,FOciError,@buf[1],length(buf),nil,0,OCI_NTV_SYNTAX,OCI_DEFAULT) = OCI_ERROR then
  302. HandleError;
  303. if assigned(AParams) then
  304. begin
  305. setlength(ParamBuffers,AParams.Count);
  306. for tel := 0 to AParams.Count-1 do
  307. begin
  308. case AParams[tel].DataType of
  309. ftInteger : begin OFieldType := SQLT_INT; OFieldSize := sizeof(integer); end;
  310. ftFloat : begin OFieldType := SQLT_FLT; OFieldSize := sizeof(double); end;
  311. ftDate, ftDateTime : begin OFieldType := SQLT_DAT; OFieldSize := 7; end;
  312. ftString : begin OFieldType := SQLT_STR; OFieldSize := 4000; end;
  313. end;
  314. parambuffers[tel].buffer := getmem(OFieldSize);
  315. parambuffers[tel].Len := OFieldSize;
  316. parambuffers[tel].Size := OFieldSize;
  317. FOciBind := nil;
  318. if AParams[tel].ParamType=ptInput then
  319. begin
  320. if OCIBindByName(FOciStmt,FOcibind,FOciError,pchar(AParams[tel].Name),length(AParams[tel].Name),ParamBuffers[tel].buffer,OFieldSize,OFieldType,@ParamBuffers[tel].ind,nil,nil,0,nil,OCI_DEFAULT )= OCI_ERROR then
  321. HandleError;
  322. end
  323. else if AParams[tel].ParamType=ptOutput then
  324. begin
  325. if OCIBindByName(FOciStmt,FOcibind,FOciError,pchar(AParams[tel].Name),length(AParams[tel].Name),nil,OFieldSize,OFieldType,nil,nil,nil,0,nil,OCI_DATA_AT_EXEC )= OCI_ERROR then
  326. HandleError;
  327. if OCIBindDynamic(FOcibind, FOciError, nil, @cbf_no_data, @parambuffers[tel], @cbf_get_data) <> OCI_SUCCESS then
  328. HandleError;
  329. end;
  330. end;
  331. end;
  332. FPrepared := True;
  333. end;
  334. end;
  335. procedure TOracleConnection.SetParameters(cursor : TSQLCursor;AParams : TParams);
  336. var SQLVarNr : integer;
  337. i : integer;
  338. f : double;
  339. year,month,day : word;
  340. db : array[0..4] of byte;
  341. pb : pbyte;
  342. s : string;
  343. begin
  344. with cursor as TOracleCursor do for SQLVarNr := 0 to High(ParamBuffers) do with AParams[SQLVarNr] do
  345. if ParamType=ptInput then
  346. begin
  347. if IsNull then parambuffers[SQLVarNr].ind := -1 else
  348. parambuffers[SQLVarNr].ind := 0;
  349. case DataType of
  350. ftInteger : begin
  351. i := asInteger;
  352. move(i,parambuffers[SQLVarNr].buffer^,sizeof(integer));
  353. end;
  354. ftFloat : begin
  355. f := asFloat;
  356. move(f,parambuffers[SQLVarNr].buffer^,sizeof(double));
  357. end;
  358. ftString : begin
  359. s := asString+#0;
  360. move(s[1],parambuffers[SQLVarNr].buffer^,length(s)+1);
  361. end;
  362. ftDate, ftDateTime: begin
  363. DecodeDate(asDateTime,year,month,day);
  364. pb := parambuffers[SQLVarNr].buffer;
  365. pb[0] := (year div 100)+100;
  366. pb[1] := (year mod 100)+100;
  367. pb[2] := month;
  368. pb[3] := day;
  369. pb[4] := 1;
  370. pb[5] := 1;
  371. pb[6] := 1;
  372. end;
  373. end;
  374. end;
  375. end;
  376. procedure TOracleConnection.UnPrepareStatement(cursor: TSQLCursor);
  377. begin
  378. if OCIStmtRelease(TOracleCursor(cursor).FOciStmt,FOciError,nil,0,OCI_DEFAULT)<> OCI_SUCCESS then
  379. HandleError();
  380. cursor.FPrepared:=False;
  381. end;
  382. procedure TOracleConnection.InternalStartDBTransaction(trans : TOracleTrans);
  383. begin
  384. if OCITransStart(trans.FOciSvcCtx,FOciError,DefaultTimeOut,trans.FOciFlags) <> OCI_SUCCESS then
  385. HandleError();
  386. end;
  387. function TOracleConnection.GetTransactionHandle(trans: TSQLHandle): pointer;
  388. begin
  389. Result := trans;
  390. end;
  391. function TOracleConnection.StartDBTransaction(trans: TSQLHandle; AParams: string): boolean;
  392. var
  393. x_flags : ub4;
  394. i : Integer;
  395. s : string;
  396. locTrans : TOracleTrans;
  397. begin
  398. locTrans := TOracleTrans(trans);
  399. if ( Length(AParams) = 0 ) then begin
  400. x_flags := OCI_TRANS_NEW or OCI_TRANS_READWRITE;
  401. end else begin
  402. x_flags := OCI_DEFAULT;
  403. i := 1;
  404. s := ExtractSubStr(AParams,i,StdWordDelims);
  405. while ( s <> '' ) do begin
  406. if ( s = 'readonly' ) then
  407. x_flags := x_flags and OCI_TRANS_READONLY
  408. else if ( s = 'serializable' ) then
  409. x_flags := x_flags and OCI_TRANS_SERIALIZABLE
  410. else if ( s = 'readwrite' ) then
  411. x_flags := x_flags and OCI_TRANS_READWRITE;
  412. s := ExtractSubStr(AParams,i,StdWordDelims);
  413. end;
  414. x_flags := x_flags and OCI_TRANS_NEW;
  415. end;
  416. locTrans.FOciFlags := x_flags;
  417. InternalStartDBTransaction(locTrans);
  418. Result := True;
  419. end;
  420. function TOracleConnection.Commit(trans: TSQLHandle): boolean;
  421. begin
  422. if OCITransCommit(TOracleTrans(trans).FOciSvcCtx,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
  423. HandleError();
  424. Result := True;
  425. end;
  426. function TOracleConnection.Rollback(trans: TSQLHandle): boolean;
  427. begin
  428. if OCITransRollback(TOracleTrans(trans).FOciSvcCtx,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
  429. HandleError();
  430. Result := True;
  431. end;
  432. procedure TOracleConnection.CommitRetaining(trans: TSQLHandle);
  433. begin
  434. Commit(trans);
  435. InternalStartDBTransaction(TOracleTrans(trans));
  436. end;
  437. procedure TOracleConnection.RollbackRetaining(trans: TSQLHandle);
  438. begin
  439. Rollback(trans);
  440. InternalStartDBTransaction(TOracleTrans(trans));
  441. end;
  442. procedure TOracleConnection.Execute(cursor: TSQLCursor; ATransaction: TSQLTransaction; AParams: TParams);
  443. begin
  444. if Assigned(APArams) and (AParams.count > 0) then SetParameters(cursor, AParams);
  445. if cursor.FStatementType = stSelect then
  446. begin
  447. if OCIStmtExecute(TOracleTrans(ATransaction.Handle).FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,0,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
  448. HandleError;
  449. end
  450. else
  451. begin
  452. if OCIStmtExecute(TOracleTrans(ATransaction.Handle).FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,1,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
  453. HandleError;
  454. if Assigned(APArams) and (AParams.count > 0) then GetParameters(cursor, AParams);
  455. end;
  456. end;
  457. function TOracleConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
  458. var rowcount: ub4;
  459. begin
  460. if OCIAttrGet((cursor as TOracleCursor).FOciStmt, OCI_HTYPE_STMT, @rowcount, nil, OCI_ATTR_ROW_COUNT, FOciError) = OCI_SUCCESS then
  461. Result:=rowcount
  462. else
  463. Result:=inherited RowsAffected(cursor);
  464. end;
  465. procedure TOracleConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TFieldDefs);
  466. var Param : POCIParam;
  467. tel : ub4;
  468. FieldType : TFieldType;
  469. FieldName : string;
  470. FieldSize : word;
  471. OFieldType : ub2;
  472. OFieldName : Pchar;
  473. OFieldSize : sb4;
  474. OFNameLength : ub4;
  475. NumCols : ub4;
  476. FOciDefine : POCIDefine;
  477. OPrecision : sb2;
  478. OScale : sb1;
  479. begin
  480. Param := nil;
  481. with cursor as TOracleCursor do
  482. begin
  483. if OCIAttrGet(FOciStmt,OCI_HTYPE_STMT,@numcols,nil,OCI_ATTR_PARAM_COUNT,FOciError) = OCI_ERROR then
  484. HandleError;
  485. // Let op, moet gewist worden. En in een keer gealloceerd
  486. Setlength(FieldBuffers,numcols);
  487. for tel := 1 to numcols do
  488. begin
  489. if OCIParamGet(FOciStmt,OCI_HTYPE_STMT,FOciError,Param,tel) = OCI_ERROR then
  490. HandleError;
  491. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldType,nil,OCI_ATTR_DATA_TYPE,FOciError) = OCI_ERROR then
  492. HandleError;
  493. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldSize,nil,OCI_ATTR_DATA_SIZE,FOciError) = OCI_ERROR then
  494. HandleError;
  495. FieldSize := 0;
  496. case OFieldType of
  497. OCI_TYPECODE_NUMBER : begin
  498. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oprecision,nil,OCI_ATTR_PRECISION,FOciError) = OCI_ERROR then
  499. HandleError;
  500. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oscale,nil,OCI_ATTR_SCALE,FOciError) = OCI_ERROR then
  501. HandleError;
  502. if Oscale = 0 then
  503. begin
  504. if Oprecision=0 then //Number(0,0) = number(32,4)
  505. begin //Warning ftBCD is limited to precision 12
  506. FieldType := ftBCD;
  507. FieldSize := 4;
  508. OFieldType := SQLT_VNU;
  509. OFieldSize:= 22;
  510. end
  511. else
  512. begin
  513. FieldType := ftInteger;
  514. OFieldType := SQLT_INT;
  515. OFieldSize:= sizeof(integer);
  516. end;
  517. end
  518. else if (oscale = -127) {and (OPrecision=0)} then
  519. begin
  520. FieldType := ftFloat;
  521. OFieldType := SQLT_FLT;
  522. OFieldSize:=sizeof(double);
  523. end
  524. else if (oscale <=4) and (OPrecision<=12) then
  525. begin
  526. FieldType := ftBCD;
  527. FieldSize := oscale;
  528. OFieldType := SQLT_VNU;
  529. OFieldSize:= 22;
  530. end
  531. else FieldType := ftUnknown;
  532. end;
  533. OCI_TYPECODE_CHAR,
  534. OCI_TYPECODE_VARCHAR,
  535. OCI_TYPECODE_VARCHAR2 : begin FieldType := ftString; FieldSize := OFieldSize; inc(OFieldsize) ;OFieldType:=SQLT_STR end;
  536. OCI_TYPECODE_DATE : FieldType := ftDate;
  537. OCI_TYPECODE_TIMESTAMP,
  538. OCI_TYPECODE_TIMESTAMP_LTZ,
  539. OCI_TYPECODE_TIMESTAMP_TZ : begin
  540. FieldType := ftDateTime;
  541. OFieldType := SQLT_ODT;
  542. end;
  543. else
  544. FieldType := ftUnknown;
  545. end;
  546. FieldBuffers[tel-1].buffer := getmem(OFieldSize);
  547. FOciDefine := nil;
  548. if OciDefineByPos(FOciStmt,FOciDefine,FOciError,tel,fieldbuffers[tel-1].buffer,OFieldSize,OFieldType,@(fieldbuffers[tel-1].ind),nil,nil,OCI_DEFAULT) = OCI_ERROR then
  549. HandleError;
  550. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldName,@OFNameLength,OCI_ATTR_NAME,FOciError) <> OCI_SUCCESS then
  551. HandleError;
  552. setlength(Fieldname,OFNameLength);
  553. move(OFieldName^,Fieldname[1],OFNameLength);
  554. TFieldDef.Create(FieldDefs, FieldDefs.MakeNameUnique(FieldName), FieldType, FieldSize, False, tel);
  555. end;
  556. end;
  557. end;
  558. function TOracleConnection.Fetch(cursor: TSQLCursor): boolean;
  559. begin
  560. case OCIStmtFetch2((cursor as TOracleCursor).FOciStmt,FOciError,1,OCI_FETCH_NEXT,1,OCI_DEFAULT) of
  561. OCI_ERROR : begin
  562. Result := False;
  563. HandleError;
  564. end;
  565. OCI_NO_DATA : Result := False;
  566. OCI_SUCCESS : Result := True;
  567. OCI_SUCCESS_WITH_INFO : Begin
  568. Result := True;
  569. HandleError;
  570. end;
  571. end; {case}
  572. end;
  573. function TOracleConnection.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef; buffer: pointer; out CreateBlob : boolean): boolean;
  574. var dt : TDateTime;
  575. b : pbyte;
  576. size,i : byte;
  577. exp : shortint;
  578. cur : Currency;
  579. odt : POCIdateTime;
  580. begin
  581. CreateBlob := False;
  582. with cursor as TOracleCursor do if fieldbuffers[FieldDef.FieldNo-1].ind = -1 then
  583. Result := False
  584. else
  585. begin
  586. result := True;
  587. case FieldDef.DataType of
  588. ftString : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,FieldDef.Size);
  589. ftBCD : begin
  590. b := fieldbuffers[FieldDef.FieldNo-1].buffer;
  591. size := b[0];
  592. cur := 0;
  593. if (b[1] and $80)=$80 then // then the number is positive
  594. begin
  595. exp := (b[1] and $7f)-65;
  596. for i := 2 to size do
  597. cur := cur + (b[i]-1) * intpower(100,-(i-2)+exp);
  598. end
  599. else
  600. begin
  601. exp := (not(b[1]) and $7f)-65;
  602. for i := 2 to size-1 do
  603. cur := cur + (101-b[i]) * intpower(100,-(i-2)+exp);
  604. cur := -cur;
  605. end;
  606. move(cur,buffer^,SizeOf(Currency));
  607. end;
  608. ftFloat : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(double));
  609. ftInteger : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(integer));
  610. ftDate : begin
  611. b := fieldbuffers[FieldDef.FieldNo-1].buffer;
  612. dt := EncodeDate((b[0]-100)*100+(b[1]-100),b[2],b[3]);
  613. move(dt,buffer^,sizeof(dt));
  614. end;
  615. ftDateTime : begin
  616. odt := fieldbuffers[FieldDef.FieldNo-1].buffer;
  617. dt := ComposeDateTime(EncodeDate(odt^.year,odt^.month,odt^.day), EncodeTime(odt^.hour,odt^.min,odt^.sec,0));
  618. move(dt,buffer^,sizeof(dt));
  619. end;
  620. else
  621. Result := False;
  622. end;
  623. end;
  624. end;
  625. {function TOracleConnection.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
  626. begin
  627. // Result:=inherited CreateBlobStream(Field, Mode);
  628. end;}
  629. procedure TOracleConnection.FreeFldBuffers(cursor: TSQLCursor);
  630. begin
  631. // inherited FreeFldBuffers(cursor);
  632. end;
  633. constructor TOracleConnection.Create(AOwner: TComponent);
  634. begin
  635. inherited Create(AOwner);
  636. FConnOptions := FConnOptions + [sqEscapeRepeat];
  637. FUserMem := nil;
  638. end;
  639. { TOracleConnectionDef }
  640. class function TOracleConnectionDef.TypeName: String;
  641. begin
  642. Result:='Oracle';
  643. end;
  644. class function TOracleConnectionDef.ConnectionClass: TSQLConnectionClass;
  645. begin
  646. Result:=TOracleConnection;
  647. end;
  648. class function TOracleConnectionDef.Description: String;
  649. begin
  650. Result:='Connect to an Oracle database directly via the client library';
  651. end;
  652. { TOracleTrans }
  653. destructor TOracleTrans.Destroy();
  654. begin
  655. OCIHandleFree(FOciTrans,OCI_HTYPE_TRANS);
  656. OCIHandleFree(FOciSvcCtx,OCI_HTYPE_SVCCTX);
  657. inherited Destroy();
  658. end;
  659. initialization
  660. RegisterConnection(TOracleConnectionDef);
  661. finalization
  662. RegisterConnection(TOracleConnectionDef);
  663. end.