oraclew.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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 OCI, oratypes,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: POCIError; 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 : POCIEnv;
  55. Err : POCIError;
  56. Svc : POCISvcCtx;
  57. Stmt: POCIStmt;
  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 : POCIParam;
  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, nil,
  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: POCIDefine;
  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. SQLT_NUM: begin
  169. if PDesc^.scale <> 0 then
  170. begin
  171. defptr := @PDesc^.flt_buf;
  172. deflen := SizeOf(PDesc^.flt_buf);
  173. deftyp := SQLT_FLT;
  174. PDesc^.dbtype := SQLT_FLT;
  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 := SQLT_INT;
  183. PDesc^.dbtype := SQLT_INT;
  184. end
  185. else begin
  186. defptr := @PDesc^.int_buf;
  187. deflen := SizeOf(PDesc^.int_buf);
  188. deftyp := SQLT_INT;
  189. PDesc^.dbtype := SQLT_INT;
  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: POCIError; msg : string );
  209. var
  210. buff : array [0..1024] of char;
  211. begin
  212. if err <> nil then
  213. begin
  214. case errcode of
  215. OCI_INVALID_HANDLE: Msg := Msg + ' OCI_INVALID_HANDLE';
  216. end;
  217. OCIErrorGet( err, 1, nil, errcode, @buff[0], 1024, OCI_HTYPE_ERROR);
  218. writeln(stderr, msg, ' ', buff);
  219. end
  220. else begin
  221. WriteLn(stderr, msg);
  222. Halt(1);
  223. end;
  224. end;
  225. procedure OraInit;
  226. begin
  227. ecode := OCIInitialize({OCI_DEFAULT or }OCI_OBJECT, nil, nil, nil, nil);
  228. if ecode <> 0 then OraError( ecode, nil, 'Error initializing OCI');
  229. ecode := OCIEnvInit(Env, OCI_DEFAULT, 0, nil);
  230. if ecode <> 0 then OraError( ecode, nil, 'Error initializing OCI environment');
  231. ecode := OCIHandleAlloc(Env, Err, OCI_HTYPE_ERROR, 0, nil);
  232. if ecode <> 0 then OraError( ecode, nil, 'Error allocating error handle');
  233. ecode := OCIHandleAlloc(Env, Stmt, OCI_HTYPE_STMT, 0, nil);
  234. if ecode <> 0 then OraError( ecode, nil, 'Error allocating statement handle');
  235. end;
  236. procedure OraLogin(name, pass, server: string);
  237. begin
  238. ecode := OCILogon(Env, Err, Svc, @name[1], Length(name),
  239. @pass[1], Length(pass), @server[1], Length(server));
  240. if ecode <> 0 then OraError(ecode, Err, '');
  241. end;
  242. procedure OraLogout;
  243. begin
  244. ecode := OCILogoff(Svc, Err);
  245. if ecode <> 0 then
  246. OraError(ecode, Err, 'OCILogoff: ');
  247. end;
  248. procedure OraFin;
  249. begin
  250. OCIHandleFree(Stmt, OCI_HTYPE_STMT);
  251. OCIHandleFree(Err, OCI_HTYPE_ERROR);
  252. end;
  253. procedure OraSQLExec(sql: string);
  254. var
  255. dtype: longint;
  256. begin
  257. // writeLn(Length(sql));
  258. ecode := OCIStmtPrepare(Stmt, Err, @sql[1], Length(sql),
  259. OCI_NTV_SYNTAX, OCI_DEFAULT);
  260. if ecode <> 0 then
  261. begin
  262. OraError(ecode, Err, 'OCIStmtPrepare:');
  263. Exit;
  264. end;
  265. dtype := cPrefetchCnt;
  266. ecode := OCIAttrSet(Stmt, OCI_HTYPE_STMT, @dtype,
  267. SizeOf(dtype), OCI_ATTR_PREFETCH_ROWS, Err);
  268. if ecode <> 0 then
  269. begin
  270. OraError(ecode, Err, 'ociattrset:');
  271. Exit;
  272. end;
  273. dtype := 0;
  274. ecode := OCIAttrGet(Stmt, OCI_HTYPE_STMT, @dtype, nil,
  275. OCI_ATTR_STMT_TYPE, Err);
  276. if ecode <> 0 then
  277. begin
  278. OraError(ecode, Err, 'ociattrget:');
  279. Exit;
  280. end;
  281. ecode := 0;
  282. if dtype = OCI_STMT_SELECT then
  283. ecode := OCIStmtExecute(Svc, Stmt, Err, 0, 0, nil, nil, OCI_DEFAULT)
  284. else ecode := OCIStmtExecute(Svc, Stmt, Err, 1, 0, nil, nil, OCI_DEFAULT);
  285. if ecode <> 0 then
  286. begin
  287. OraError(ecode, Err, 'OCIStmtExecute:');
  288. Exit;
  289. end;
  290. if dtype = OCI_STMT_SELECT then
  291. begin
  292. Describe;
  293. Define;
  294. end;
  295. end;
  296. function OraGetFieldCount : integer;
  297. begin
  298. OraGetFieldCount := FieldList.Count;
  299. end;
  300. function IsFieldDate(Pos : integer): boolean;
  301. var
  302. Desc : TDescribeRec;
  303. begin
  304. Result := False;
  305. if (Pos > FieldList.Count) or (Pos < 1) then
  306. Exit;
  307. Desc := TDescribeRec(FieldList[Pos-1]^);
  308. Result := (Desc.dbtype = SQLT_DAT);
  309. end;
  310. function OraGetFieldAsString(pos : integer) : string;
  311. var
  312. Desc : TDescribeRec;
  313. Date : array [0..6] of byte;
  314. begin
  315. if (Pos > FieldList.Count) or (Pos < 1) then
  316. Exit;
  317. Desc := TDescribeRec(FieldList[pos-1]^);
  318. if Desc.indp < 0 then
  319. begin
  320. OraGetFieldAsString := 'null';
  321. Exit;
  322. end;
  323. if Desc.dbtype = SQLT_STR then
  324. begin
  325. Desc.valbuf[Desc.col_retlen] := #0;
  326. OraGetFieldAsString := strpas(Desc.valbuf);
  327. end
  328. else if Desc.dbtype = SQLT_CHR then
  329. begin
  330. Desc.valbuf[Desc.col_retlen] := #0;
  331. OraGetFieldAsString := strpas(Desc.valbuf);
  332. end
  333. else if Desc.dbtype = SQLT_INT then
  334. begin
  335. OraGetFieldAsString := IntToStr(Desc.int_buf);
  336. end
  337. else if Desc.dbtype = SQLT_FLT then
  338. OraGetFieldAsString := FloatToStr(Desc.flt_buf)
  339. else if Desc.dbtype = SQLT_DAT then
  340. begin
  341. Move(Desc.valbuf,Date,SizeOf(Date));
  342. OraGetFieldAsString :=
  343. Format('%0.2d.%0.2d.%0.4d %0.2d:%0.2d:%0.2d',
  344. [Date[3],Date[2],(((Date[0]-100)*100)+(Date[1] - 100)),
  345. Date[4]-1,
  346. Date[5]-1,
  347. Date[6]-1]);
  348. end
  349. else if Desc.dbtype = SQLT_AFC then
  350. begin
  351. Desc.valbuf[Desc.col_retlen] := #0;
  352. OraGetFieldAsString := strpas(Desc.valbuf);
  353. end
  354. else OraGetFieldAsString := 'dbtype not implemented ' + IntToStr(Desc.dbtype);
  355. end;
  356. function OraGetFieldAsInteger(pos : integer) : longint;
  357. begin
  358. OraGetFieldAsInteger := 0;
  359. end;
  360. function OraNext: boolean;
  361. begin
  362. ecode := OCIStmtFetch(Stmt, Err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
  363. if ecode = 0 then
  364. OraNext := true
  365. else if ecode = OCI_SUCCESS_WITH_INFO then
  366. OraNext := false
  367. else if ecode = OCI_NO_DATA then
  368. OraNext := false
  369. else begin
  370. OraNext := false;
  371. OraError(ecode, err, 'OCIStmtFetch:');
  372. end;
  373. end;
  374. function OraGetFieldType(pos : integer) : longint;
  375. begin
  376. if (Pos > FieldList.Count) or (pos < 1) then
  377. Exit;
  378. OraGetFieldType := TDescribeRec(FieldList[pos-1]^).dbtype;
  379. end;
  380. function OraGetFieldName(pos : integer) : string;
  381. begin
  382. if (Pos > FieldList.Count) or (Pos < 1) then
  383. Exit;
  384. OraGetFieldName := strpas(TDescribeRec(FieldList[pos-1]^).buf);
  385. end;
  386. initialization
  387. FieldList := TList.Create;
  388. finalization
  389. FieldListClear;
  390. FieldList.Free;
  391. end.