oraclew.pp 13 KB

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