oracleconnection.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. unit OracleConnection;
  2. {$mode objfpc}{$H+}
  3. {$Define LinkDynamically}
  4. interface
  5. uses
  6. Classes, SysUtils, sqldb,db,dbconst,
  7. {$IfDef LinkDynamically}
  8. ocidyn,
  9. {$ELSE}
  10. oci,
  11. {$ENDIF}
  12. oratypes;
  13. type
  14. TOracleTrans = Class(TSQLHandle)
  15. protected
  16. end;
  17. TOraFieldBuf = record
  18. Buffer : pointer;
  19. Ind : sb2;
  20. end;
  21. TOracleCursor = Class(TSQLCursor)
  22. protected
  23. FOciStmt : POCIStmt;
  24. FieldBuffers : array of TOraFieldBuf;
  25. ParamBuffers : array of TOraFieldBuf;
  26. end;
  27. { TOracleConnection }
  28. TOracleConnection = class (TSQLConnection)
  29. private
  30. FOciEnvironment : POciEnv;
  31. FOciError : POCIError;
  32. FOciSvcCtx : POCISvcCtx;
  33. FUserMem : pointer;
  34. procedure HandleError;
  35. procedure SetParameters(cursor : TSQLCursor;AParams : TParams);
  36. protected
  37. // - Connect/disconnect
  38. procedure DoInternalConnect; override;
  39. procedure DoInternalDisconnect; override;
  40. // - Handle (de)allocation
  41. function AllocateCursorHandle:TSQLCursor; override;
  42. procedure DeAllocateCursorHandle(var cursor:TSQLCursor); override;
  43. function AllocateTransactionHandle:TSQLHandle; override;
  44. // - Statement handling
  45. procedure PrepareStatement(cursor:TSQLCursor; ATransaction:TSQLTransaction; buf:string; AParams:TParams); override;
  46. procedure UnPrepareStatement(cursor:TSQLCursor); override;
  47. // - Transaction handling
  48. function GetTransactionHandle(trans:TSQLHandle):pointer; override;
  49. function StartDBTransaction(trans:TSQLHandle; AParams:string):boolean; override;
  50. function Commit(trans:TSQLHandle):boolean; override;
  51. function Rollback(trans:TSQLHandle):boolean; override;
  52. procedure CommitRetaining(trans:TSQLHandle); override;
  53. procedure RollbackRetaining(trans:TSQLHandle); override;
  54. // - Statement execution
  55. procedure Execute(cursor:TSQLCursor; ATransaction:TSQLTransaction; AParams:TParams); override;
  56. // - Result retrieving
  57. procedure AddFieldDefs(cursor:TSQLCursor; FieldDefs:TFieldDefs); override;
  58. function Fetch(cursor:TSQLCursor):boolean; override;
  59. function LoadField(cursor:TSQLCursor; FieldDef:TFieldDef; buffer:pointer):boolean; override;
  60. function CreateBlobStream(Field:TField; Mode:TBlobStreamMode):TStream; override;
  61. procedure FreeFldBuffers(cursor:TSQLCursor); override;
  62. public
  63. constructor Create(AOwner : TComponent); override;
  64. end;
  65. implementation
  66. ResourceString
  67. SErrEnvCreateFailed = 'The creation of an Oracle environment failed.';
  68. SErrHandleAllocFailed = 'The allocation of the error handle failed.';
  69. SErrOracle = 'Oracle returned error %s:';
  70. procedure TOracleConnection.HandleError;
  71. var errcode : sb4;
  72. buf : array[0..1023] of char;
  73. begin
  74. OCIErrorGet(FOciError,1,nil,errcode,@buf[1],1023,OCI_HTYPE_ERROR);
  75. DatabaseErrorFmt(SErrOracle+LineEnding+buf,[inttostr(errcode)],self);
  76. end;
  77. procedure TOracleConnection.DoInternalConnect;
  78. begin
  79. {$IfDef LinkDynamically}
  80. InitialiseOCI;
  81. {$EndIf}
  82. inherited DoInternalConnect;
  83. FUserMem := nil;
  84. if OCIEnvCreate(FOciEnvironment,oci_default,nil,nil,nil,nil,0,FUserMem) <> OCI_SUCCESS then
  85. DatabaseError(SErrEnvCreateFailed,self);
  86. if OciHandleAlloc(FOciEnvironment,FOciError,OCI_HTYPE_ERROR,0,FUserMem) <> OCI_SUCCESS then
  87. DatabaseError(SErrHandleAllocFailed,self);
  88. if OCILogon2(FOciEnvironment,FOciError,FOciSvcCtx,@username[1],length(username),@password[1],length(password),@databasename[1],length(databasename),OCI_DEFAULT) = OCI_ERROR then
  89. HandleError;
  90. end;
  91. procedure TOracleConnection.DoInternalDisconnect;
  92. begin
  93. inherited DoInternalDisconnect;
  94. if OCILogoff(FOciSvcCtx,FOciError)<> OCI_SUCCESS then
  95. HandleError;
  96. OCIHandleFree(FOciSvcCtx,OCI_HTYPE_SVCCTX);
  97. OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
  98. OCIHandleFree(FOciEnvironment,OCI_HTYPE_ENV);
  99. {$IfDef LinkDynamically}
  100. ReleaseOCI;
  101. {$EndIf}
  102. end;
  103. function TOracleConnection.AllocateCursorHandle: TSQLCursor;
  104. var Cursor : TOracleCursor;
  105. begin
  106. Cursor:=TOracleCursor.Create;
  107. OciHandleAlloc(FOciEnvironment,Cursor.FOciStmt,OCI_HTYPE_STMT,0,FUserMem);
  108. Result := cursor;
  109. end;
  110. procedure TOracleConnection.DeAllocateCursorHandle(var cursor: TSQLCursor);
  111. var tel : word;
  112. begin
  113. with cursor as TOracleCursor do
  114. begin
  115. OCIHandleFree(FOciStmt,OCI_HTYPE_ERROR);
  116. if Length(FieldBuffers) > 0 then
  117. for tel := 0 to high(FieldBuffers) do freemem(FieldBuffers[tel].buffer);
  118. end;
  119. FreeAndNil(cursor);
  120. end;
  121. function TOracleConnection.AllocateTransactionHandle: TSQLHandle;
  122. begin
  123. Result:=nil;
  124. end;
  125. procedure TOracleConnection.PrepareStatement(cursor: TSQLCursor;
  126. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  127. var tel : integer;
  128. FOcibind : POCIDefine;
  129. OFieldType : ub2;
  130. OFieldSize : sb4;
  131. begin
  132. with cursor as TOracleCursor do
  133. begin
  134. if OCIStmtPrepare(FOciStmt,FOciError,@buf[1],length(buf),OCI_NTV_SYNTAX,OCI_DEFAULT) = OCI_ERROR then
  135. HandleError;
  136. if assigned(AParams) then
  137. begin
  138. setlength(ParamBuffers,AParams.Count);
  139. for tel := 0 to AParams.Count-1 do
  140. begin
  141. case AParams[tel].DataType of
  142. ftInteger : begin OFieldType := SQLT_INT; OFieldSize := sizeof(integer); end;
  143. ftFloat : begin OFieldType := SQLT_FLT; OFieldSize := sizeof(double); end;
  144. ftDate, ftDateTime : begin OFieldType := SQLT_DAT; OFieldSize := 7; end;
  145. ftString : begin OFieldType := SQLT_STR; OFieldSize := 4000; end;
  146. end;
  147. parambuffers[tel].buffer := getmem(OFieldSize);
  148. FOciBind := nil;
  149. 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
  150. HandleError;
  151. end;
  152. end;
  153. end;
  154. end;
  155. procedure TOracleConnection.SetParameters(cursor : TSQLCursor;AParams : TParams);
  156. var SQLVarNr : integer;
  157. i : integer;
  158. f : double;
  159. year,month,day : word;
  160. db : array[0..4] of byte;
  161. pb : pbyte;
  162. s : string;
  163. begin
  164. with cursor as TOracleCursor do for SQLVarNr := 0 to High(ParamBuffers) do with AParams[SQLVarNr] do
  165. begin
  166. if IsNull then parambuffers[SQLVarNr].ind := -1 else
  167. parambuffers[SQLVarNr].ind := 0;
  168. case DataType of
  169. ftInteger : begin
  170. i := asInteger;
  171. move(i,parambuffers[SQLVarNr].buffer^,sizeof(integer));
  172. end;
  173. ftFloat : begin
  174. f := asFloat;
  175. move(f,parambuffers[SQLVarNr].buffer^,sizeof(double));
  176. end;
  177. ftString : begin
  178. s := asString+#0;
  179. move(s[1],parambuffers[SQLVarNr].buffer^,length(s)+1);
  180. end;
  181. ftDate, ftDateTime: begin
  182. DecodeDate(asDateTime,year,month,day);
  183. pb := parambuffers[SQLVarNr].buffer;
  184. pb[0] := (year div 100)+100;
  185. pb[1] := (year mod 100)+100;
  186. pb[2] := month;
  187. pb[3] := day;
  188. pb[4] := 1;
  189. pb[5] := 1;
  190. pb[6] := 1;
  191. end;
  192. end;
  193. end;
  194. end;
  195. procedure TOracleConnection.UnPrepareStatement(cursor: TSQLCursor);
  196. begin
  197. //
  198. end;
  199. function TOracleConnection.GetTransactionHandle(trans: TSQLHandle): pointer;
  200. begin
  201. // Transactions not implemented yet
  202. end;
  203. function TOracleConnection.StartDBTransaction(trans: TSQLHandle; AParams: string): boolean;
  204. begin
  205. // Transactions not implemented yet
  206. end;
  207. function TOracleConnection.Commit(trans: TSQLHandle): boolean;
  208. begin
  209. // Transactions not implemented yet
  210. end;
  211. function TOracleConnection.Rollback(trans: TSQLHandle): boolean;
  212. begin
  213. // Transactions not implemented yet
  214. end;
  215. procedure TOracleConnection.CommitRetaining(trans: TSQLHandle);
  216. begin
  217. // Transactions not implemented yet
  218. end;
  219. procedure TOracleConnection.RollbackRetaining(trans: TSQLHandle);
  220. begin
  221. // Transactions not implemented yet
  222. end;
  223. procedure TOracleConnection.Execute(cursor: TSQLCursor; ATransaction: TSQLTransaction; AParams: TParams);
  224. begin
  225. if Assigned(APArams) and (AParams.count > 0) then SetParameters(cursor, AParams);
  226. if cursor.FStatementType = stSelect then
  227. begin
  228. if OCIStmtExecute(FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,0,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
  229. HandleError;
  230. end
  231. else
  232. begin
  233. if OCIStmtExecute(FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,1,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
  234. HandleError;
  235. end;
  236. end;
  237. procedure TOracleConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TFieldDefs);
  238. var Param : POCIParam;
  239. tel : ub4;
  240. FieldType : TFieldType;
  241. FieldName : string;
  242. FieldSize : word;
  243. OFieldType : ub2;
  244. OFieldName : Pchar;
  245. OFieldSize : sb4;
  246. OFNameLength : ub4;
  247. NumCols : ub4;
  248. FOciDefine : POCIDefine;
  249. OPrecision : sb2;
  250. OScale : sb1;
  251. begin
  252. Param := nil;
  253. with cursor as TOracleCursor do
  254. begin
  255. if OCIAttrGet(FOciStmt,OCI_HTYPE_STMT,@numcols,nil,OCI_ATTR_PARAM_COUNT,FOciError) = OCI_ERROR then
  256. HandleError;
  257. // Let op, moet gewist worden. En in een keer gealloceerd
  258. Setlength(FieldBuffers,numcols);
  259. for tel := 1 to numcols do
  260. begin
  261. if OCIParamGet(FOciStmt,OCI_HTYPE_STMT,FOciError,Param,tel) = OCI_ERROR then
  262. HandleError;
  263. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldType,nil,OCI_ATTR_DATA_TYPE,FOciError) = OCI_ERROR then
  264. HandleError;
  265. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldSize,nil,OCI_ATTR_DATA_SIZE,FOciError) = OCI_ERROR then
  266. HandleError;
  267. FieldSize := 0;
  268. case OFieldType of
  269. OCI_TYPECODE_NUMBER : begin
  270. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oprecision,nil,OCI_ATTR_PRECISION,FOciError) = OCI_ERROR then
  271. HandleError;
  272. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oscale,nil,OCI_ATTR_SCALE,FOciError) = OCI_ERROR then
  273. HandleError;
  274. if Oscale = 0 then
  275. begin
  276. FieldType := ftInteger;
  277. OFieldType := SQLT_INT;
  278. OFieldSize:= sizeof(integer);
  279. end
  280. else if (oscale = -127) and (OPrecision=0) then
  281. begin
  282. FieldType := ftFloat;
  283. OFieldType := SQLT_FLT;
  284. OFieldSize:=sizeof(double);
  285. end;
  286. end;
  287. OCI_TYPECODE_CHAR,
  288. OCI_TYPECODE_VARCHAR,
  289. OCI_TYPECODE_VARCHAR2 : begin FieldType := ftString; inc(OFieldsize) ;FieldSize := OFieldSize; OFieldType:=SQLT_STR end;
  290. OCI_TYPECODE_DATE : FieldType := ftDate;
  291. else
  292. FieldType := ftUnknown;
  293. end;
  294. FieldBuffers[tel-1].buffer := getmem(OFieldSize);
  295. FOciDefine := nil;
  296. if OciDefineByPos(FOciStmt,FOciDefine,FOciError,tel,fieldbuffers[tel-1].buffer,OFieldSize,OFieldType,@(fieldbuffers[tel-1].ind),nil,nil,OCI_DEFAULT) = OCI_ERROR then
  297. HandleError;
  298. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldName,@OFNameLength,OCI_ATTR_NAME,FOciError) <> OCI_SUCCESS then
  299. HandleError;
  300. setlength(Fieldname,OFNameLength);
  301. move(OFieldName^,Fieldname[1],OFNameLength);
  302. TFieldDef.Create(FieldDefs, FieldName, FieldType, FieldSize, False, tel);
  303. end;
  304. end;
  305. end;
  306. function TOracleConnection.Fetch(cursor: TSQLCursor): boolean;
  307. begin
  308. case OCIStmtFetch2((cursor as TOracleCursor).FOciStmt,FOciError,1,OCI_FETCH_NEXT,1,OCI_DEFAULT) of
  309. OCI_ERROR : begin
  310. Result := False;
  311. HandleError;
  312. end;
  313. OCI_NO_DATA : Result := False;
  314. OCI_SUCCESS : Result := True;
  315. OCI_SUCCESS_WITH_INFO : Begin
  316. Result := True;
  317. HandleError;
  318. end;
  319. end; {case}
  320. end;
  321. function TOracleConnection.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef; buffer: pointer): boolean;
  322. var dt : TDateTime;
  323. b : pbyte;
  324. begin
  325. with cursor as TOracleCursor do if fieldbuffers[FieldDef.FieldNo-1].ind = -1 then
  326. Result := False
  327. else
  328. begin
  329. result := True;
  330. case FieldDef.DataType of
  331. ftString : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,FieldDef.Size);
  332. ftFloat : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(double));
  333. ftInteger : move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(integer));
  334. ftDate : begin
  335. b := fieldbuffers[FieldDef.FieldNo-1].buffer;
  336. dt := EncodeDate((b[0]-100)*100+(b[1]-100),b[2],b[3]);
  337. move(dt,buffer^,sizeof(dt));
  338. end;
  339. else
  340. Result := False;
  341. end;
  342. end;
  343. end;
  344. function TOracleConnection.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
  345. begin
  346. // Result:=inherited CreateBlobStream(Field, Mode);
  347. end;
  348. procedure TOracleConnection.FreeFldBuffers(cursor: TSQLCursor);
  349. begin
  350. // inherited FreeFldBuffers(cursor);
  351. end;
  352. constructor TOracleConnection.Create(AOwner: TComponent);
  353. begin
  354. inherited Create(AOwner);
  355. FUserMem := nil;
  356. end;
  357. end.