oraclew.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. {
  2. $Id$
  3. Copyright (c) 1999-2000 by Pavel Stingl <[email protected]>
  4. OCI workaround
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit oraclew;
  12. interface
  13. {$H+}
  14. {$mode objfpc}
  15. uses OraOCI, Classes, SysUtils;
  16. { all pos parameters are indexed from 1..x! }
  17. procedure OraInit;
  18. procedure OraFin;
  19. procedure OraLogin(name, pass, server: string);
  20. procedure OraLogout;
  21. procedure OraSQLExec(sql: string);
  22. function OraGetFieldAsString(pos : integer) : string;
  23. function OraGetFieldAsInteger(pos : integer) : longint;
  24. function OraNext: boolean;
  25. function OraGetFieldCount: integer;
  26. function OraGetFieldName(pos : integer) : string;
  27. function OraGetFieldType(pos : integer) : longint;
  28. function IsFieldDate(Pos : integer): boolean;
  29. procedure OraError(errcode: integer; err: OCIError; msg : string);
  30. const
  31. cDescribeBuf = 1024;
  32. cPCharBufLen = 4097;
  33. cPrefetchCnt = 100;
  34. type
  35. PDescribeRec = ^TDescribeRec;
  36. TDescribeRec = record
  37. dbsize : sb4;
  38. dbtype : sb2;
  39. buf : array [0..cDescribeBuf] of char;
  40. buflen : sb4;
  41. dsize : sb4;
  42. precision : sb2;
  43. scale : sb2;
  44. nullok : sb2;
  45. // Define part
  46. valbuf : array [0..cDescribeBuf] of char;
  47. flt_buf : double;
  48. int_buf : cardinal;
  49. int64_buf : int64;
  50. indp : sb2;
  51. col_retlen: ub2;
  52. col_retcode: ub2;
  53. end;
  54. var
  55. Env : OCIEnv;
  56. Err : OCIError;
  57. Svc : OCISvcCtx;
  58. Stmt: OCIStmt;
  59. FieldList : TList;
  60. ecode : integer;
  61. implementation
  62. function DecodeDataType(dtype : longint): string;
  63. begin
  64. case dtype of
  65. SQLT_CHR : DecodeDataType := '(ORANET TYPE) character string';
  66. SQLT_NUM : DecodeDataType := '(ORANET TYPE) oracle numeric';
  67. SQLT_INT : DecodeDataType := '(ORANET TYPE) integer';
  68. SQLT_FLT : DecodeDataType := '(ORANET TYPE) Floating point number';
  69. SQLT_STR : DecodeDataType := 'zero terminated string';
  70. SQLT_VNU : DecodeDataType := 'NUM with preceding length byte';
  71. SQLT_PDN : DecodeDataType := '(ORANET TYPE) Packed Decimal Numeric';
  72. SQLT_LNG : DecodeDataType := 'long';
  73. SQLT_VCS : DecodeDataType := 'Variable character string';
  74. SQLT_NON : DecodeDataType := 'Null/empty PCC Descriptor entry';
  75. SQLT_RID : DecodeDataType := 'rowid';
  76. SQLT_DAT : DecodeDataType := 'date in oracle format';
  77. SQLT_VBI : DecodeDataType := 'binary in VCS format';
  78. SQLT_BIN : DecodeDataType := 'binary data(DTYBIN)';
  79. SQLT_LBI : DecodeDataType := 'long binary';
  80. SQLT_UIN : DecodeDataType := 'unsigned integer';
  81. SQLT_SLS : DecodeDataType := 'Display sign leading separate';
  82. SQLT_LVC : DecodeDataType := 'Longer longs (char)';
  83. SQLT_LVB : DecodeDataType := 'Longer long binary';
  84. SQLT_AFC : DecodeDataType := 'Ansi fixed char';
  85. SQLT_AVC : DecodeDataType := 'Ansi Var char';
  86. SQLT_CUR : DecodeDataType := 'cursor type';
  87. SQLT_RDD : DecodeDataType := 'rowid descriptor';
  88. SQLT_LAB : DecodeDataType := 'label type';
  89. SQLT_OSL : DecodeDataType := 'oslabel type';
  90. SQLT_NTY : DecodeDataType := 'named object type';
  91. SQLT_REF : DecodeDataType := 'ref type';
  92. SQLT_CLOB : DecodeDataType := 'character lob';
  93. SQLT_BLOB : DecodeDataType := 'binary lob';
  94. SQLT_BFILEE : DecodeDataType := 'binary file lob';
  95. SQLT_CFILEE : DecodeDataType := 'character file lob';
  96. SQLT_RSET : DecodeDataType := 'result set type';
  97. SQLT_NCO : DecodeDataType := 'named collection type (varray or nested table)';
  98. SQLT_VST : DecodeDataType := 'OCIString type';
  99. SQLT_ODT : DecodeDataType := 'OCIDate type';
  100. else DecodeDataType := 'Unknown';
  101. end;
  102. end;
  103. procedure FieldListClear;
  104. var
  105. x: longint;
  106. PDesc: PDescribeRec;
  107. begin
  108. if FieldList.Count = 0 then Exit;
  109. for x := 0 to FieldList.Count - 1 do
  110. begin
  111. PDesc := FieldList[x];
  112. Dispose(PDesc);
  113. end;
  114. FieldList.Clear;
  115. end;
  116. procedure Describe;
  117. var
  118. fldc : longint;
  119. paramd : OCIParam;
  120. colname : PChar;
  121. colsize : ub4;
  122. Rec : PDescribeRec;
  123. begin
  124. fldc := 1;
  125. FieldListClear;
  126. ecode := OCIParamGet(Stmt, OCI_HTYPE_STMT, Err, @paramd, fldc);
  127. if ecode <> OCI_SUCCESS then
  128. ORAError(ecode, Err, 'OCIParamGetError');
  129. while ecode = OCI_SUCCESS do
  130. begin
  131. New(Rec);
  132. FillChar(Rec^.buf, sizeof(Rec^.buf), #0);
  133. ecode := OCIAttrGet(paramd, OCI_DTYPE_PARAM, @Rec^.dbtype, 0,
  134. OCI_ATTR_DATA_TYPE, Err);
  135. if ecode <> 0 then
  136. begin
  137. ORAError(ecode, Err, 'Retrieving DTYPE_PARAM:');
  138. end;
  139. colsize := 0;
  140. colname := nil;
  141. ecode := OCIAttrGet(paramd, OCI_DTYPE_PARAM, @colname, @colsize,
  142. OCI_ATTR_NAME, Err);
  143. if ecode <> 0 then
  144. begin
  145. ORAError(ecode, Err, 'Retrieving DTYPE_PARAM:');
  146. end;
  147. Move(Colname^,Rec^.buf, colsize);
  148. Rec^.buflen := colsize;
  149. // WriteLn('Column: ',Rec^.buf:15,' DataType: ',DecodeDataType(Rec^.dbtype));
  150. inc(fldc);
  151. FieldList.Add(Rec);
  152. ecode := OCIParamGet(Stmt, OCI_HTYPE_STMT, Err, @paramd, fldc);
  153. end;
  154. end;
  155. procedure Define;
  156. var
  157. x : longint;
  158. def: OCIDefine;
  159. PDesc : PDescribeRec;
  160. defptr: pointer;
  161. deflen: sword;
  162. deftyp: sword;
  163. begin
  164. def := nil;
  165. for x := 0 to FieldList.Count - 1 do
  166. begin
  167. PDesc := FieldList[x];
  168. case PDesc^.dbtype of
  169. NUMBER_TYPE: begin
  170. if PDesc^.scale <> 0 then
  171. begin
  172. defptr := @PDesc^.flt_buf;
  173. deflen := SizeOf(PDesc^.flt_buf);
  174. deftyp := FLOAT_TYPE;
  175. PDesc^.dbtype := FLOAT_TYPE;
  176. end
  177. else begin
  178. if PDesc^.dbsize > 4 then
  179. begin
  180. // WriteLn('BIG FAT WARNING!!!! dbsize int > 4 (',PDesc^.dbsize,')');
  181. defptr := @PDesc^.int64_buf;
  182. deflen := SizeOf(PDesc^.int64_buf);
  183. deftyp := INT_TYPE;
  184. PDesc^.dbtype := INT_TYPE;
  185. end
  186. else begin
  187. defptr := @PDesc^.int_buf;
  188. deflen := SizeOf(PDesc^.int_buf);
  189. deftyp := INT_TYPE;
  190. PDesc^.dbtype := INT_TYPE;
  191. end;
  192. end;
  193. end;
  194. else begin
  195. defptr := @PDesc^.valbuf;
  196. deflen := cDescribeBuf;
  197. deftyp := PDesc^.dbtype;
  198. end;
  199. end;
  200. ecode := OCIDefineByPos(Stmt, @def, Err, x + 1, defptr,
  201. deflen, deftyp, @PDesc^.indp, @PDesc^.col_retlen,
  202. @PDesc^.col_retcode, OCI_DEFAULT);
  203. if ecode <> 0 then
  204. begin
  205. OraError(ecode, Err, 'OCIDefineByPos: ');
  206. end;
  207. end;
  208. end;
  209. procedure OraError( errcode : integer; err: OCIError; msg : string );
  210. var
  211. buff : array [0..1024] of char;
  212. xp : PLongint;
  213. begin
  214. if err <> nil then
  215. begin
  216. case errcode of
  217. OCI_INVALID_HANDLE: Msg := Msg + ' OCI_INVALID_HANDLE';
  218. end;
  219. xp := @errcode;
  220. OCIErrorGet( err, 1, nil, xp, @buff[0], 1024, OCI_HTYPE_ERROR);
  221. writeln(stderr, msg, ' ', buff);
  222. end
  223. else begin
  224. WriteLn(stderr, msg);
  225. Halt(1);
  226. end;
  227. end;
  228. procedure OraInit;
  229. begin
  230. ecode := OCIInitialize({OCI_DEFAULT or }OCI_OBJECT, nil, nil, nil, nil);
  231. if ecode <> 0 then OraError( ecode, nil, 'Error initializing OCI');
  232. ecode := OCIEnvInit(Env, OCI_DEFAULT, 0, nil);
  233. if ecode <> 0 then OraError( ecode, nil, 'Error initializing OCI environment');
  234. ecode := OCIHandleAlloc(Env, Err, OCI_HTYPE_ERROR, 0, nil);
  235. if ecode <> 0 then OraError( ecode, nil, 'Error allocating error handle');
  236. ecode := OCIHandleAlloc(Env, Stmt, OCI_HTYPE_STMT, 0, nil);
  237. if ecode <> 0 then OraError( ecode, nil, 'Error allocating statement handle');
  238. end;
  239. procedure OraLogin(name, pass, server: string);
  240. begin
  241. ecode := OCILogon(Env, Err, Svc, @name[1], Length(name),
  242. @pass[1], Length(pass), @server[1], Length(server));
  243. if ecode <> 0 then OraError(ecode, Err, '');
  244. end;
  245. procedure OraLogout;
  246. begin
  247. ecode := OCILogoff(Svc, Err);
  248. if ecode <> 0 then
  249. OraError(ecode, Err, 'OCILogoff: ');
  250. end;
  251. procedure OraFin;
  252. begin
  253. OCIHandleFree(Stmt, OCI_HTYPE_STMT);
  254. OCIHandleFree(Err, OCI_HTYPE_ERROR);
  255. end;
  256. procedure OraSQLExec(sql: string);
  257. var
  258. dtype: longint;
  259. begin
  260. // writeLn(Length(sql));
  261. ecode := OCIStmtPrepare(Stmt, Err, @sql[1], Length(sql),
  262. OCI_NTV_SYNTAX, OCI_DEFAULT);
  263. if ecode <> 0 then
  264. begin
  265. OraError(ecode, Err, 'OCIStmtPrepare:');
  266. Exit;
  267. end;
  268. dtype := cPrefetchCnt;
  269. ecode := OCIAttrSet(Stmt, OCI_HTYPE_STMT, @dtype,
  270. SizeOf(dtype), OCI_ATTR_PREFETCH_ROWS, Err);
  271. if ecode <> 0 then
  272. begin
  273. OraError(ecode, Err, 'ociattrset:');
  274. Exit;
  275. end;
  276. dtype := 0;
  277. ecode := OCIAttrGet(Stmt, OCI_HTYPE_STMT, @dtype, 4,
  278. OCI_ATTR_STMT_TYPE, Err);
  279. if ecode <> 0 then
  280. begin
  281. OraError(ecode, Err, 'ociattrget:');
  282. Exit;
  283. end;
  284. ecode := 0;
  285. if dtype = OCI_STMT_SELECT then
  286. ecode := OCIStmtExecute(Svc, Stmt, Err, 0, 0, nil, nil, OCI_DEFAULT)
  287. else ecode := OCIStmtExecute(Svc, Stmt, Err, 1, 0, nil, nil, OCI_DEFAULT);
  288. if ecode <> 0 then
  289. begin
  290. OraError(ecode, Err, 'OCIStmtExecute:');
  291. Exit;
  292. end;
  293. if dtype = OCI_STMT_SELECT then
  294. begin
  295. Describe;
  296. Define;
  297. end;
  298. end;
  299. function OraGetFieldCount : integer;
  300. begin
  301. OraGetFieldCount := FieldList.Count;
  302. end;
  303. function IsFieldDate(Pos : integer): boolean;
  304. var
  305. Desc : TDescribeRec;
  306. begin
  307. Result := False;
  308. if (Pos > FieldList.Count) or (Pos < 1) then
  309. Exit;
  310. Desc := TDescribeRec(FieldList[Pos-1]^);
  311. Result := (Desc.dbtype = DATE_TYPE);
  312. end;
  313. function OraGetFieldAsString(pos : integer) : string;
  314. var
  315. Desc : TDescribeRec;
  316. Date : array [0..6] of byte;
  317. begin
  318. if (Pos > FieldList.Count) or (Pos < 1) then
  319. Exit;
  320. Desc := TDescribeRec(FieldList[pos-1]^);
  321. if Desc.indp < 0 then
  322. begin
  323. OraGetFieldAsString := 'null';
  324. Exit;
  325. end;
  326. if Desc.dbtype = STRING_TYPE then
  327. begin
  328. Desc.valbuf[Desc.col_retlen] := #0;
  329. OraGetFieldAsString := Desc.valbuf;
  330. end
  331. else if Desc.dbtype = VARCHAR2_TYPE then
  332. begin
  333. Desc.valbuf[Desc.col_retlen] := #0;
  334. OraGetFieldAsString := Desc.valbuf;
  335. end
  336. else if Desc.dbtype = INT_TYPE then
  337. begin
  338. OraGetFieldAsString := IntToStr(Desc.int_buf);
  339. end
  340. else if Desc.dbtype = FLOAT_TYPE then
  341. OraGetFieldAsString := FloatToStr(Desc.flt_buf)
  342. else if Desc.dbtype = DATE_TYPE then
  343. begin
  344. Move(Desc.valbuf,Date,SizeOf(Date));
  345. OraGetFieldAsString :=
  346. Format('%0.2d.%0.2d.%0.4d %0.2d:%0.2d:%0.2d',
  347. [Date[3],Date[2],(((Date[0]-100)*100)+(Date[1] - 100)),
  348. Date[4]-1,
  349. Date[5]-1,
  350. Date[6]-1]);
  351. end
  352. else if Desc.dbtype = SQLT_AFC then
  353. begin
  354. Desc.valbuf[Desc.col_retlen] := #0;
  355. OraGetFieldAsString := Desc.valbuf;
  356. end
  357. else OraGetFieldAsString := 'dbtype not implemented ' + IntToStr(Desc.dbtype);
  358. end;
  359. function OraGetFieldAsInteger(pos : integer) : longint;
  360. begin
  361. OraGetFieldAsInteger := 0;
  362. end;
  363. function OraNext: boolean;
  364. begin
  365. ecode := OCIStmtFetch(Stmt, Err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
  366. if ecode = 0 then
  367. OraNext := true
  368. else if ecode = OCI_SUCCESS_WITH_INFO then
  369. OraNext := false
  370. else if ecode = OCI_NO_DATA then
  371. OraNext := false
  372. else begin
  373. OraNext := false;
  374. OraError(ecode, err, 'OCIStmtFetch:');
  375. end;
  376. end;
  377. function OraGetFieldType(pos : integer) : longint;
  378. begin
  379. if (Pos > FieldList.Count) or (pos < 1) then
  380. Exit;
  381. OraGetFieldType := TDescribeRec(FieldList[pos-1]^).dbtype;
  382. end;
  383. function OraGetFieldName(pos : integer) : string;
  384. begin
  385. if (Pos > FieldList.Count) or (Pos < 1) then
  386. Exit;
  387. OraGetFieldName := TDescribeRec(FieldList[pos-1]^).buf;
  388. end;
  389. initialization
  390. FieldList := TList.Create;
  391. finalization
  392. FieldListClear;
  393. FieldList.Free;
  394. end.
  395. {
  396. $Log$
  397. Revision 1.1 2002-01-29 17:54:54 peter
  398. * splitted to base and extra
  399. Revision 1.1 2001/04/08 12:23:49 peter
  400. * moved oraclew and test01 to example subdir to remove the dependency
  401. on the fcl. This dependency is now only required when building the
  402. examples
  403. Revision 1.1 2000/12/02 15:14:14 michael
  404. + Initial implementation of Pavel Stingl
  405. Revision 1.1.1.1 2000/10/11 07:48:28 stingp1
  406. * Import to cvs
  407. }