oracleconnection.pp 26 KB

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