2
0

oracleconnection.pp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  1. unit oracleconnection;
  2. {
  3. Copyright (c) 2006-2014 by Joost van der Sluis, FPC contributors
  4. Oracle RDBMS connector using the OCI protocol
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. **********************************************************************}
  8. {$mode objfpc}{$H+}
  9. {$Define LinkDynamically}
  10. interface
  11. uses
  12. Classes, SysUtils, db, dbconst, sqldb, bufdataset,
  13. {$IfDef LinkDynamically}
  14. ocidyn,
  15. {$ELSE}
  16. oci,
  17. {$ENDIF}
  18. oratypes;
  19. const
  20. DefaultTimeOut = 60;
  21. type
  22. EOraDatabaseError = class(ESQLDatabaseError)
  23. public
  24. property ORAErrorCode: integer read ErrorCode; deprecated 'Please use ErrorCode instead of ORAErrorCode'; // June 2014
  25. end;
  26. TOracleTrans = Class(TSQLHandle)
  27. protected
  28. FOciSvcCtx : POCISvcCtx;
  29. FOciTrans : POCITrans;
  30. FOciFlags : ub4;
  31. public
  32. destructor Destroy(); override;
  33. end;
  34. TOraFieldBuf = record
  35. DescType : ub4; // descriptor type
  36. Buffer : pointer;
  37. Ind : sb2; // indicator
  38. Len : ub4;
  39. Size : ub4;
  40. end;
  41. TOracleCursor = Class(TSQLCursor)
  42. protected
  43. FOciStmt : POCIStmt;
  44. FieldBuffers : array of TOraFieldBuf;
  45. ParamBuffers : array of TOraFieldBuf;
  46. end;
  47. { TOracleConnection }
  48. TOracleConnection = class (TSQLConnection)
  49. private
  50. FOciEnvironment : POciEnv;
  51. FOciError : POCIError;
  52. FOciServer : POCIServer;
  53. FOciUserSession : POCISession;
  54. FUserMem : pointer;
  55. procedure HandleError;
  56. procedure GetParameters(cursor : TSQLCursor; AParams : TParams);
  57. procedure SetParameters(cursor : TSQLCursor; AParams : TParams);
  58. protected
  59. // - Connect/disconnect
  60. procedure DoInternalConnect; override;
  61. procedure DoInternalDisconnect; override;
  62. // - Handle (de)allocation
  63. function AllocateCursorHandle:TSQLCursor; override;
  64. procedure DeAllocateCursorHandle(var cursor:TSQLCursor); override;
  65. function AllocateTransactionHandle:TSQLHandle; override;
  66. // - Statement handling
  67. procedure PrepareStatement(cursor:TSQLCursor; ATransaction:TSQLTransaction; buf:string; AParams:TParams); override;
  68. procedure UnPrepareStatement(cursor:TSQLCursor); override;
  69. // - Transaction handling
  70. procedure InternalStartDBTransaction(trans:TOracleTrans);
  71. function GetTransactionHandle(trans:TSQLHandle):pointer; override;
  72. function StartDBTransaction(trans:TSQLHandle; AParams:string):boolean; override;
  73. function Commit(trans:TSQLHandle):boolean; override;
  74. function Rollback(trans:TSQLHandle):boolean; override;
  75. procedure CommitRetaining(trans:TSQLHandle); override;
  76. procedure RollbackRetaining(trans:TSQLHandle); override;
  77. // - Statement execution
  78. procedure Execute(cursor:TSQLCursor; ATransaction:TSQLTransaction; AParams:TParams); override;
  79. function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
  80. // - Result retrieval
  81. procedure AddFieldDefs(cursor:TSQLCursor; FieldDefs:TFieldDefs); override;
  82. function Fetch(cursor:TSQLCursor):boolean; override;
  83. function LoadField(cursor:TSQLCursor; FieldDef:TFieldDef; buffer:pointer; out CreateBlob : boolean):boolean; override;
  84. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction); override;
  85. procedure FreeFldBuffers(cursor:TSQLCursor); override;
  86. procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); override;
  87. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
  88. public
  89. constructor Create(AOwner : TComponent); override;
  90. end;
  91. { TOracleConnectionDef }
  92. TOracleConnectionDef = Class(TConnectionDef)
  93. Class Function TypeName : String; override;
  94. Class Function ConnectionClass : TSQLConnectionClass; override;
  95. Class Function Description : String; override;
  96. Class Function DefaultLibraryName : String; override;
  97. Class Function LoadFunction : TLibraryLoadFunction; override;
  98. Class Function UnLoadFunction : TLibraryUnLoadFunction; override;
  99. Class Function LoadedLibraryName: string; override;
  100. end;
  101. implementation
  102. uses
  103. math, StrUtils, FmtBCD;
  104. const
  105. ObjectQuote='"'; //beginning and ending quote for objects such as table names. Note: can be different from quotes around field names
  106. ResourceString
  107. SErrEnvCreateFailed = 'The creation of an Oracle environment failed.';
  108. SErrHandleAllocFailed = 'The allocation of the error handle failed.';
  109. SErrOracle = 'Oracle returned error %s:';
  110. type
  111. TODateTime = record
  112. year : sb2;
  113. month : ub1;
  114. day : ub1;
  115. hour : ub1;
  116. min : ub1;
  117. sec : ub1;
  118. fsec : ub4;
  119. end;
  120. // Callback functions
  121. function cbf_no_data(ictxp:Pdvoid; bindp:POCIBind; iter:ub4; index:ub4; bufpp:PPdvoid;
  122. alenp:Pub4; piecep:Pub1; indp:PPdvoid):sb4;cdecl;
  123. begin
  124. bufpp^ := nil;
  125. alenp^ := 0;
  126. indp^ := nil;
  127. piecep^ := OCI_ONE_PIECE;
  128. result:=OCI_CONTINUE;
  129. end;
  130. function cbf_get_data(octxp:Pdvoid; bindp:POCIBind; iter:ub4; index:ub4; bufpp:PPdvoid;
  131. alenp:PPub4; piecep:Pub1; indp:PPdvoid; rcodep:PPub2):sb4;cdecl;
  132. begin
  133. // Only 1 row can be stored. No support for multiple rows: only the last row is kept.
  134. bufpp^:=TOraFieldBuf(octxp^).Buffer;
  135. indp^ := @TOraFieldBuf(octxp^).Ind;
  136. TOraFieldBuf(octxp^).Len:=TOraFieldBuf(octxp^).Size; //reset size to full buffer
  137. alenp^ := @TOraFieldBuf(octxp^).Len;
  138. rcodep^:=nil;
  139. piecep^ := OCI_ONE_PIECE;
  140. result:=OCI_CONTINUE;
  141. end;
  142. // Conversions
  143. Procedure FmtBCD2Nvu(bcd:tBCD;b:pByte);
  144. var
  145. i,j,cnt : integer;
  146. nibbles : array [0..maxfmtbcdfractionsize-1] of byte;
  147. exp : shortint;
  148. bb : byte;
  149. begin
  150. fillchar(b[0],22,#0);
  151. if BCDPrecision(bcd)=0 then // zero, special case
  152. begin
  153. b[0]:=1;
  154. b[1]:=$80;
  155. end
  156. else
  157. begin
  158. if (BCDPrecision(bcd)-BCDScale(bcd)) mod 2 <>0 then // odd number before decimal point
  159. begin
  160. nibbles[0]:=0;
  161. j:=1;
  162. end
  163. else
  164. j:=0;
  165. for i:=0 to bcd.Precision -1 do
  166. if i mod 2 =0 then
  167. nibbles[i+j]:=bcd.Fraction[i div 2] shr 4
  168. else
  169. nibbles[i+j]:=bcd.Fraction[i div 2] and $0f;
  170. nibbles[bcd.Precision+j]:=0; // make sure last nibble is also 0 in case we have odd scale
  171. exp:=(BCDPrecision(bcd)-BCDScale(bcd)+1) div 2;
  172. cnt:=exp+(BCDScale(bcd)+1) div 2;
  173. // to avoid "ora 01438: value larger than specified precision allowed for this column"
  174. // remove trailing zeros (scale < 0)...
  175. while (nibbles[cnt*2-2]*10+nibbles[cnt*2-1])=0 do
  176. cnt:=cnt-1;
  177. // ... and remove leading zeros (scale > precision)
  178. j:=0;
  179. while (nibbles[j*2]*10+nibbles[j*2+1])=0 do
  180. begin
  181. j:=j+1;
  182. exp:=exp-1;
  183. end;
  184. if IsBCDNegative(bcd) then
  185. begin
  186. b[0]:=cnt-j+1;
  187. b[1]:=not(exp+64) and $7f ;
  188. for i:=j to cnt-1 do
  189. begin
  190. bb:=nibbles[i*2]*10+nibbles[i*2+1];
  191. b[2+i-j]:=101-bb;
  192. end;
  193. if 2+cnt-j<22 then // add a 102 at the end of the number if place left.
  194. begin
  195. b[0]:=b[0]+1;
  196. b[2+cnt-j]:=102;
  197. end;
  198. end
  199. else
  200. begin
  201. b[0]:=cnt-j+1;
  202. b[1]:=(exp+64) or $80 ;
  203. for i:=j to cnt-1 do
  204. begin
  205. bb:=nibbles[i*2]*10+nibbles[i*2+1];
  206. b[2+i-j]:=1+bb;
  207. end;
  208. end;
  209. end;
  210. end;
  211. function Nvu2FmtBCE(b:pbyte):tBCD;
  212. var
  213. i,j : integer;
  214. bb,size : byte;
  215. exp : shortint;
  216. nibbles : array [0..maxfmtbcdfractionsize-1] of byte;
  217. scale : integer;
  218. begin
  219. size := b[0];
  220. if (size=1) and (b[1]=$80) then // special representation for 0
  221. result:=IntegerToBCD(0)
  222. else
  223. begin
  224. result.SignSpecialPlaces:=0; //sign positive, non blank, scale 0
  225. result.Precision:=1; //BCDNegate works only if Precision <>0
  226. if (b[1] and $80)=$80 then // then the number is positive
  227. begin
  228. exp := (b[1] and $7f)-65;
  229. for i := 0 to size-2 do
  230. begin
  231. bb := b[i+2]-1;
  232. nibbles[i*2]:=bb div 10;
  233. nibbles[i*2+1]:=(bb mod 10);
  234. end;
  235. end
  236. else
  237. begin
  238. BCDNegate(result);
  239. exp := (not(b[1]) and $7f)-65;
  240. if b[size]=102 then // last byte doesn't count if = 102
  241. size:=size-1;
  242. for i := 0 to size-2 do
  243. begin
  244. bb := 101-b[i+2];
  245. nibbles[i*2]:=bb div 10;
  246. nibbles[i*2+1]:=(bb mod 10);
  247. end;
  248. end;
  249. nibbles[(size-1)*2]:=0;
  250. result.Precision:=(size-1)*2;
  251. scale:=result.Precision-(exp*2+2);
  252. if scale>=0 then
  253. begin
  254. if (scale>result.Precision) then // need to add leading 0s
  255. begin
  256. for i:=0 to (scale-result.Precision+1) div 2 do
  257. result.Fraction[i]:=0;
  258. i:=scale-result.Precision;
  259. result.Precision:=scale;
  260. end
  261. else
  262. i:=0;
  263. j:=i;
  264. if (i=0) and (nibbles[0]=0) then // get rid of leading zero received from oci
  265. begin
  266. result.Precision:=result.Precision-1;
  267. j:=-1;
  268. end;
  269. while i<=result.Precision do // copy nibbles
  270. begin
  271. if i mod 2 =0 then
  272. result.Fraction[i div 2]:=nibbles[i-j] shl 4
  273. else
  274. result.Fraction[i div 2]:=result.Fraction[i div 2] or nibbles[i-j];
  275. i:=i+1;
  276. end;
  277. result.SignSpecialPlaces:=result.SignSpecialPlaces or scale;
  278. end
  279. else
  280. begin // add trailing zeroes, increase precision to take them into account
  281. i:=0;
  282. while i<=result.Precision do // copy nibbles
  283. begin
  284. if i mod 2 =0 then
  285. result.Fraction[i div 2]:=nibbles[i] shl 4
  286. else
  287. result.Fraction[i div 2]:=result.Fraction[i div 2] or nibbles[i];
  288. i:=i+1;
  289. end;
  290. result.Precision:=result.Precision-scale;
  291. for i := size -1 to High(result.Fraction) do
  292. result.Fraction[i] := 0;
  293. end;
  294. end;
  295. end;
  296. // TOracleConnection
  297. procedure TOracleConnection.HandleError;
  298. var errcode : sb4;
  299. buf : array[0..1023] of char;
  300. E : EOraDatabaseError;
  301. begin
  302. OCIErrorGet(FOciError,1,nil,errcode,@buf[0],1024,OCI_HTYPE_ERROR);
  303. if (Self.Name <> '') then
  304. E := EOraDatabaseError.CreateFmt('%s : %s',[Self.Name,pchar(buf)])
  305. else
  306. E := EOraDatabaseError.Create(pchar(buf));
  307. E.ErrorCode := errcode;
  308. Raise E;
  309. end;
  310. procedure TOracleConnection.GetParameters(cursor: TSQLCursor; AParams: TParams);
  311. var
  312. i : integer;
  313. odt : TODateTime;
  314. s : string;
  315. begin
  316. with cursor as TOracleCursor do for i := 0 to High(ParamBuffers) do
  317. with AParams[i] do
  318. if ParamType=ptOutput then
  319. begin
  320. if ParamBuffers[i].ind = -1 then
  321. Value:=null;
  322. case DataType of
  323. ftInteger : AsInteger := PInteger(ParamBuffers[i].buffer)^;
  324. ftFloat : AsFloat := PDouble(ParamBuffers[i].buffer)^;
  325. ftString : begin
  326. SetLength(s,ParamBuffers[i].Len);
  327. move(ParamBuffers[i].buffer^,s[1],length(s)+1);
  328. AsString:=s;
  329. end;
  330. ftDate, ftDateTime: begin
  331. OCIDateTimeGetDate(FOciUserSession, FOciError, ParamBuffers[i].buffer, @odt.year, @odt.month, @odt.day);
  332. OCIDateTimeGetTime(FOciUserSession, FOciError, ParamBuffers[i].buffer, @odt.hour, @odt.min, @odt.sec, @odt.fsec);
  333. AsDateTime := ComposeDateTime(EncodeDate(odt.year,odt.month,odt.day), EncodeTime(odt.hour,odt.min,odt.sec,odt.fsec div 1000000));
  334. end;
  335. ftFMTBcd : begin
  336. AsFMTBCD:=Nvu2FmtBCE(ParamBuffers[i].buffer);
  337. end;
  338. end;
  339. end;
  340. end;
  341. procedure TOracleConnection.DoInternalConnect;
  342. var
  343. ConnectString : string;
  344. TempServiceContext : POCISvcCtx;
  345. begin
  346. {$IfDef LinkDynamically}
  347. InitialiseOCI;
  348. {$EndIf}
  349. inherited DoInternalConnect;
  350. //todo: get rid of FUserMem, as it isn't used
  351. FUserMem := nil;
  352. // Create environment handle
  353. if OCIEnvCreate(FOciEnvironment,oci_default,nil,nil,nil,nil,0,FUserMem) <> OCI_SUCCESS then
  354. DatabaseError(SErrEnvCreateFailed,self);
  355. // Create error handle
  356. if OciHandleAlloc(FOciEnvironment,FOciError,OCI_HTYPE_ERROR,0,FUserMem) <> OCI_SUCCESS then
  357. DatabaseError(SErrHandleAllocFailed,self);
  358. // Create Server handle
  359. if OciHandleAlloc(FOciEnvironment,FOciServer,OCI_HTYPE_SERVER,0,FUserMem) <> OCI_SUCCESS then
  360. DatabaseError(SErrHandleAllocFailed,self);
  361. // Initialize Server handle
  362. if hostname='' then connectstring := databasename
  363. else connectstring := '//'+hostname+'/'+databasename;
  364. if OCIServerAttach(FOciServer,FOciError,@(ConnectString[1]),Length(ConnectString),OCI_DEFAULT) <> OCI_SUCCESS then
  365. HandleError();
  366. // Create temporary service-context handle for user authentication
  367. if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
  368. DatabaseError(SErrHandleAllocFailed,self);
  369. // Create user-session handle
  370. if OciHandleAlloc(FOciEnvironment,FOciUserSession,OCI_HTYPE_SESSION,0,FUserMem) <> OCI_SUCCESS then
  371. DatabaseError(SErrHandleAllocFailed,self);
  372. // Set the server-handle in the service-context handle
  373. if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
  374. HandleError();
  375. // Set username and password in the user-session handle
  376. if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.UserName[1]),Length(Self.UserName),OCI_ATTR_USERNAME,FOciError) <> OCI_SUCCESS then
  377. HandleError();
  378. if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.Password[1]),Length(Self.Password),OCI_ATTR_PASSWORD,FOciError) <> OCI_SUCCESS then
  379. HandleError();
  380. // Authenticate
  381. if OCISessionBegin(TempServiceContext,FOciError,FOcIUserSession,OCI_CRED_RDBMS,OCI_DEFAULT) <> OCI_SUCCESS then
  382. HandleError();
  383. // Free temporary service-context handle
  384. OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
  385. end;
  386. procedure TOracleConnection.DoInternalDisconnect;
  387. var
  388. TempServiceContext : POCISvcCtx;
  389. begin
  390. inherited DoInternalDisconnect;
  391. // Create temporary service-context handle for user-disconnect
  392. if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
  393. DatabaseError(SErrHandleAllocFailed,self);
  394. // Set the server handle in the service-context handle
  395. if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
  396. HandleError();
  397. // Set the user session handle in the service-context handle
  398. if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then
  399. HandleError();
  400. // Disconnect uses-session handle
  401. if OCISessionEnd(TempServiceContext,FOciError,FOcIUserSession,OCI_DEFAULT) <> OCI_SUCCESS then
  402. HandleError();
  403. // Free user-session handle
  404. OCIHandleFree(FOciUserSession,OCI_HTYPE_SESSION);
  405. // Free temporary service-context handle
  406. OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
  407. // Disconnect server handle
  408. if OCIServerDetach(FOciServer,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
  409. HandleError();
  410. // Free connection handles
  411. OCIHandleFree(FOciServer,OCI_HTYPE_SERVER);
  412. OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
  413. OCIHandleFree(FOciEnvironment,OCI_HTYPE_ENV);
  414. {$IfDef LinkDynamically}
  415. ReleaseOCI;
  416. {$EndIf}
  417. end;
  418. function TOracleConnection.AllocateCursorHandle: TSQLCursor;
  419. var
  420. Cursor : TOracleCursor;
  421. begin
  422. Cursor:=TOracleCursor.Create;
  423. Result := cursor;
  424. end;
  425. procedure TOracleConnection.DeAllocateCursorHandle(var cursor: TSQLCursor);
  426. procedure FreeOraFieldBuffers(b: array of TOraFieldBuf);
  427. var i : integer;
  428. begin
  429. if Length(b) > 0 then
  430. for i := low(b) to high(b) do
  431. if b[i].DescType <> 0 then
  432. OciDescriptorFree(b[i].buffer, b[i].DescType)
  433. else
  434. freemem(b[i].buffer);
  435. end;
  436. begin
  437. with cursor as TOracleCursor do
  438. begin
  439. FreeOraFieldBuffers(FieldBuffers);
  440. FreeOraFieldBuffers(ParamBuffers);
  441. end;
  442. FreeAndNil(cursor);
  443. end;
  444. function TOracleConnection.AllocateTransactionHandle: TSQLHandle;
  445. var
  446. locRes : TOracleTrans;
  447. begin
  448. locRes := TOracleTrans.Create();
  449. try
  450. // Allocate service-context handle
  451. if OciHandleAlloc(FOciEnvironment,locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
  452. DatabaseError(SErrHandleAllocFailed,self);
  453. // Set the server-handle in the service-context handle
  454. if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
  455. HandleError();
  456. // Set the user-session handle in the service-context handle
  457. if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then
  458. HandleError();
  459. // Allocate transaction handle
  460. if OciHandleAlloc(FOciEnvironment,locRes.FOciTrans,OCI_HTYPE_TRANS,0,FUserMem) <> OCI_SUCCESS then
  461. DatabaseError(SErrHandleAllocFailed,self);
  462. // Set the transaction handle in the service-context handle
  463. if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,locRes.FOciTrans,0,OCI_ATTR_TRANS,FOciError) <> OCI_SUCCESS then
  464. HandleError();
  465. except
  466. locRes.Free();
  467. raise;
  468. end;
  469. Result := locRes;
  470. end;
  471. procedure TOracleConnection.PrepareStatement(cursor: TSQLCursor;
  472. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  473. var i : integer;
  474. FOcibind : POCIDefine;
  475. OFieldType : ub2;
  476. OFieldSize : sb4;
  477. ODescType : ub4;
  478. OBuffer : pointer;
  479. stmttype : ub2;
  480. begin
  481. with cursor as TOracleCursor do
  482. begin
  483. if OCIStmtPrepare2(TOracleTrans(ATransaction.Handle).FOciSvcCtx,FOciStmt,FOciError,@buf[1],length(buf),nil,0,OCI_NTV_SYNTAX,OCI_DEFAULT) = OCI_ERROR then
  484. HandleError;
  485. // Get statement type
  486. if OCIAttrGet(FOciStmt,OCI_HTYPE_STMT,@stmttype,nil,OCI_ATTR_STMT_TYPE,FOciError) = OCI_ERROR then
  487. HandleError;
  488. case stmttype of
  489. OCI_STMT_SELECT: FStatementType := stSelect;
  490. OCI_STMT_UPDATE: FStatementType := stUpdate;
  491. OCI_STMT_DELETE: FStatementType := stDelete;
  492. OCI_STMT_INSERT: FStatementType := stInsert;
  493. OCI_STMT_CREATE,
  494. OCI_STMT_DROP,
  495. OCI_STMT_DECLARE,
  496. OCI_STMT_ALTER: FStatementType := stDDL;
  497. else
  498. FStatementType := stUnknown;
  499. end;
  500. if FStatementType in [stUpdate,stDelete,stInsert,stDDL] then
  501. FSelectable:=false;
  502. if assigned(AParams) then
  503. begin
  504. setlength(ParamBuffers,AParams.Count);
  505. for i := 0 to AParams.Count-1 do
  506. begin
  507. ODescType := 0;
  508. case AParams[i].DataType of
  509. ftSmallInt, ftInteger :
  510. begin OFieldType := SQLT_INT; OFieldSize := sizeof(integer); end;
  511. ftLargeInt :
  512. begin OFieldType := SQLT_INT; OFieldSize := sizeof(int64); end;
  513. ftFloat :
  514. begin OFieldType := SQLT_FLT; OFieldSize := sizeof(double); end;
  515. ftDate, ftDateTime :
  516. begin OFieldType := SQLT_TIMESTAMP; OFieldSize := sizeof(pointer); ODescType := OCI_DTYPE_TIMESTAMP; end;
  517. ftFixedChar, ftString :
  518. begin OFieldType := SQLT_STR; OFieldSize := 4000; end;
  519. ftFMTBcd, ftBCD :
  520. begin OFieldType := SQLT_VNU; OFieldSize := 22; end;
  521. ftBlob :
  522. begin OFieldType := SQLT_LVB; OFieldSize := 65535; end;
  523. ftMemo :
  524. begin OFieldType := SQLT_LVC; OFieldSize := 65535; end;
  525. else
  526. DatabaseErrorFmt(SUnsupportedParameter,[Fieldtypenames[AParams[i].DataType]],self);
  527. end;
  528. ParamBuffers[i].DescType := ODescType;
  529. ParamBuffers[i].Len := OFieldSize;
  530. ParamBuffers[i].Size := OFieldSize;
  531. if ODescType <> 0 then
  532. begin
  533. OBuffer := @ParamBuffers[i].buffer;
  534. OCIDescriptorAlloc(FOciEnvironment, OBuffer, ODescType, 0, nil);
  535. end
  536. else
  537. begin
  538. OBuffer := getmem(OFieldSize);
  539. ParamBuffers[i].buffer := OBuffer;
  540. end;
  541. FOciBind := nil;
  542. if AParams[i].ParamType=ptInput then
  543. begin
  544. if OCIBindByName(FOciStmt,FOcibind,FOciError,pchar(AParams[i].Name),length(AParams[i].Name),OBuffer,OFieldSize,OFieldType,@ParamBuffers[i].ind,nil,nil,0,nil,OCI_DEFAULT )= OCI_ERROR then
  545. HandleError;
  546. end
  547. else if AParams[i].ParamType=ptOutput then
  548. begin
  549. if OCIBindByName(FOciStmt,FOcibind,FOciError,pchar(AParams[i].Name),length(AParams[i].Name),nil,OFieldSize,OFieldType,nil,nil,nil,0,nil,OCI_DATA_AT_EXEC )= OCI_ERROR then
  550. HandleError;
  551. if OCIBindDynamic(FOcibind, FOciError, nil, @cbf_no_data, @parambuffers[i], @cbf_get_data) <> OCI_SUCCESS then
  552. HandleError;
  553. end;
  554. end;
  555. end;
  556. FPrepared := True;
  557. end;
  558. end;
  559. procedure TOracleConnection.SetParameters(cursor : TSQLCursor; AParams : TParams);
  560. var i : integer;
  561. year, month, day, hour, min, sec, msec : word;
  562. s : string;
  563. blobbuf : string;
  564. bloblen : ub4;
  565. begin
  566. with cursor as TOracleCursor do for i := 0 to High(ParamBuffers) do with AParams[i] do
  567. if ParamType=ptInput then
  568. begin
  569. if IsNull then ParamBuffers[i].ind := -1 else ParamBuffers[i].ind := 0;
  570. case DataType of
  571. ftSmallInt,
  572. ftInteger : PInteger(ParamBuffers[i].buffer)^ := AsInteger;
  573. ftLargeInt : PInt64(ParamBuffers[i].buffer)^ := AsLargeInt;
  574. ftFloat : PDouble(ParamBuffers[i].buffer)^ := AsFloat;
  575. ftString,
  576. ftFixedChar : begin
  577. s := asString+#0;
  578. move(s[1],parambuffers[i].buffer^,length(s)+1);
  579. end;
  580. ftDate, ftDateTime: begin
  581. DecodeDate(asDateTime,year,month,day);
  582. DecodeTime(asDateTime,hour,min,sec,msec);
  583. if OCIDateTimeConstruct(FOciUserSession, FOciError, ParamBuffers[i].buffer, year, month, day, hour, min, sec, msec*1000000, nil, 0) = OCI_ERROR then
  584. HandleError;
  585. { pb := ParamBuffers[i].buffer;
  586. pb[0] := (year div 100)+100;
  587. pb[1] := (year mod 100)+100;
  588. pb[2] := month;
  589. pb[3] := day;
  590. pb[4] := hour+1;
  591. pb[5] := minute+1;
  592. pb[6] := second+1;
  593. }
  594. end;
  595. ftFmtBCD, ftBCD : begin
  596. FmtBCD2Nvu(asFmtBCD,parambuffers[i].buffer);
  597. end;
  598. ftBlob, ftMemo : begin
  599. blobbuf := AsBlob; // todo: use AsBytes
  600. bloblen := length(blobbuf);
  601. if bloblen > 65531 then bloblen := 65531;
  602. PInteger(ParamBuffers[i].Buffer)^ := bloblen;
  603. Move(blobbuf[1], (ParamBuffers[i].Buffer+sizeof(integer))^, bloblen);
  604. //if OciLobWrite(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, ParamBuffers[i].buffer, @bloblen, 1, @blobbuf[1], bloblen, OCI_ONE_PIECE, nil, nil, 0, SQLCS_IMPLICIT) = OCI_ERROR then
  605. // HandleError;
  606. end;
  607. else
  608. DatabaseErrorFmt(SUnsupportedParameter,[DataType],self);
  609. end;
  610. end;
  611. end;
  612. procedure TOracleConnection.UnPrepareStatement(cursor: TSQLCursor);
  613. begin
  614. if OCIStmtRelease(TOracleCursor(cursor).FOciStmt,FOciError,nil,0,OCI_DEFAULT)<> OCI_SUCCESS then
  615. HandleError();
  616. cursor.FPrepared:=False;
  617. end;
  618. procedure TOracleConnection.InternalStartDBTransaction(trans : TOracleTrans);
  619. begin
  620. if OCITransStart(trans.FOciSvcCtx,FOciError,DefaultTimeOut,trans.FOciFlags) <> OCI_SUCCESS then
  621. HandleError();
  622. end;
  623. function TOracleConnection.GetTransactionHandle(trans: TSQLHandle): pointer;
  624. begin
  625. Result := trans;
  626. end;
  627. function TOracleConnection.StartDBTransaction(trans: TSQLHandle; AParams: string): boolean;
  628. var
  629. x_flags : ub4;
  630. i : Integer;
  631. s : string;
  632. locTrans : TOracleTrans;
  633. begin
  634. locTrans := TOracleTrans(trans);
  635. if ( Length(AParams) = 0 ) then begin
  636. x_flags := OCI_TRANS_NEW or OCI_TRANS_READWRITE;
  637. end else begin
  638. x_flags := OCI_DEFAULT;
  639. i := 1;
  640. s := ExtractSubStr(AParams,i,StdWordDelims);
  641. while ( s <> '' ) do begin
  642. if ( s = 'readonly' ) then
  643. x_flags := x_flags and OCI_TRANS_READONLY
  644. else if ( s = 'serializable' ) then
  645. x_flags := x_flags and OCI_TRANS_SERIALIZABLE
  646. else if ( s = 'readwrite' ) then
  647. x_flags := x_flags and OCI_TRANS_READWRITE;
  648. s := ExtractSubStr(AParams,i,StdWordDelims);
  649. end;
  650. x_flags := x_flags and OCI_TRANS_NEW;
  651. end;
  652. locTrans.FOciFlags := x_flags;
  653. InternalStartDBTransaction(locTrans);
  654. Result := True;
  655. end;
  656. function TOracleConnection.Commit(trans: TSQLHandle): boolean;
  657. begin
  658. if OCITransCommit(TOracleTrans(trans).FOciSvcCtx,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
  659. HandleError();
  660. Result := True;
  661. end;
  662. function TOracleConnection.Rollback(trans: TSQLHandle): boolean;
  663. begin
  664. if OCITransRollback(TOracleTrans(trans).FOciSvcCtx,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
  665. HandleError();
  666. Result := True;
  667. end;
  668. procedure TOracleConnection.CommitRetaining(trans: TSQLHandle);
  669. begin
  670. Commit(trans);
  671. InternalStartDBTransaction(TOracleTrans(trans));
  672. end;
  673. procedure TOracleConnection.RollbackRetaining(trans: TSQLHandle);
  674. begin
  675. Rollback(trans);
  676. InternalStartDBTransaction(TOracleTrans(trans));
  677. end;
  678. procedure TOracleConnection.Execute(cursor: TSQLCursor; ATransaction: TSQLTransaction; AParams: TParams);
  679. begin
  680. if Assigned(AParams) and (AParams.Count > 0) then SetParameters(cursor, AParams);
  681. if cursor.FStatementType = stSelect then
  682. begin
  683. if OCIStmtExecute(TOracleTrans(ATransaction.Handle).FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,0,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
  684. HandleError;
  685. end
  686. else
  687. begin
  688. if OCIStmtExecute(TOracleTrans(ATransaction.Handle).FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,1,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
  689. HandleError;
  690. if Assigned(AParams) and (AParams.Count > 0) then GetParameters(cursor, AParams);
  691. end;
  692. end;
  693. function TOracleConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
  694. var rowcount: ub4;
  695. begin
  696. if Assigned(cursor) and (OCIAttrGet((cursor as TOracleCursor).FOciStmt, OCI_HTYPE_STMT, @rowcount, nil, OCI_ATTR_ROW_COUNT, FOciError) = OCI_SUCCESS) then
  697. Result:=rowcount
  698. else
  699. Result:=inherited RowsAffected(cursor);
  700. end;
  701. procedure TOracleConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TFieldDefs);
  702. var Param : POCIParam;
  703. counter : ub4;
  704. FieldType : TFieldType;
  705. FieldName : string;
  706. FieldSize : cardinal;
  707. OFieldType : ub2;
  708. OFieldName : Pchar;
  709. OFieldSize : ub4;
  710. OFNameLength : ub4;
  711. NumCols : ub4;
  712. FOciDefine : POCIDefine;
  713. OPrecision : sb2;
  714. OScale : sb1;
  715. ODescType : ub4;
  716. OBuffer : pointer;
  717. begin
  718. Param := nil;
  719. with cursor as TOracleCursor do
  720. begin
  721. if OCIAttrGet(FOciStmt,OCI_HTYPE_STMT,@numcols,nil,OCI_ATTR_PARAM_COUNT,FOciError) = OCI_ERROR then
  722. HandleError;
  723. // Note: needs to be cleared then allocated in one go.
  724. Setlength(FieldBuffers,numcols);
  725. for counter := 1 to numcols do
  726. begin
  727. // Clear OFieldSize. Oracle 9i, 10g doc says *ub4 but some clients use *ub2 leaving
  728. // high 16 bit untouched resulting in huge values and ORA-01062
  729. // WARNING: this does not work on big endian systems !!!!
  730. // To be tested if BE systems have this *ub2<->*ub4 problem
  731. OFieldSize:=0;
  732. ODescType :=0;
  733. if OCIParamGet(FOciStmt,OCI_HTYPE_STMT,FOciError,Param,counter) = OCI_ERROR then
  734. HandleError;
  735. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldType,nil,OCI_ATTR_DATA_TYPE,FOciError) = OCI_ERROR then
  736. HandleError;
  737. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldSize,nil,OCI_ATTR_DATA_SIZE,FOciError) = OCI_ERROR then
  738. HandleError;
  739. FieldSize := 0;
  740. case OFieldType of
  741. OCI_TYPECODE_NUMBER : begin
  742. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oprecision,nil,OCI_ATTR_PRECISION,FOciError) = OCI_ERROR then
  743. HandleError;
  744. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oscale,nil,OCI_ATTR_SCALE,FOciError) = OCI_ERROR then
  745. HandleError;
  746. if (Oscale = 0) and (Oprecision < 10) then
  747. begin
  748. if Oprecision=0 then //Number(0,0) = number(32,4)
  749. begin
  750. FieldType := ftFMTBCD;
  751. FieldSize := 4;
  752. OFieldType := SQLT_VNU;
  753. OFieldSize:= 22;
  754. end
  755. else if Oprecision < 5 then
  756. begin
  757. FieldType := ftSmallint;
  758. OFieldType := SQLT_INT;
  759. OFieldSize := sizeof(smallint);
  760. end
  761. else // OPrecision=5..9, OScale=0
  762. begin
  763. FieldType := ftInteger;
  764. OFieldType := SQLT_INT;
  765. OFieldSize:= sizeof(integer);
  766. end;
  767. end
  768. else if (Oscale = -127) {and (OPrecision=0)} then
  769. begin
  770. FieldType := ftFloat;
  771. OFieldType := SQLT_FLT;
  772. OFieldSize:=sizeof(double);
  773. end
  774. else if (Oscale >=0) and (Oscale <=4) and (OPrecision<=12) then
  775. begin
  776. FieldType := ftBCD;
  777. FieldSize := oscale;
  778. OFieldType := SQLT_VNU;
  779. OFieldSize:= 22;
  780. end
  781. else if (OPrecision-Oscale<64) and (Oscale < 64) then // limited to 63 digits before or after decimal point
  782. begin
  783. FieldType := ftFMTBCD;
  784. FieldSize := oscale;
  785. OFieldType := SQLT_VNU;
  786. OFieldSize:= 22;
  787. end
  788. else // approximation with double, best we can do
  789. begin
  790. FieldType := ftFloat;
  791. OFieldType := SQLT_FLT;
  792. OFieldSize:=sizeof(double);
  793. end;
  794. end;
  795. SQLT_LNG,
  796. OCI_TYPECODE_CHAR,
  797. OCI_TYPECODE_VARCHAR,
  798. OCI_TYPECODE_VARCHAR2 : begin
  799. FieldType := ftString;
  800. FieldSize := OFieldSize;
  801. inc(OFieldSize);
  802. OFieldType:=SQLT_STR;
  803. end;
  804. OCI_TYPECODE_DATE : FieldType := ftDate;
  805. OCI_TYPECODE_TIMESTAMP,
  806. OCI_TYPECODE_TIMESTAMP_LTZ,
  807. OCI_TYPECODE_TIMESTAMP_TZ :
  808. begin
  809. FieldType := ftDateTime;
  810. OFieldType := SQLT_TIMESTAMP;
  811. ODescType := OCI_DTYPE_TIMESTAMP;
  812. end;
  813. OCI_TYPECODE_BFLOAT,
  814. OCI_TYPECODE_BDOUBLE : begin
  815. FieldType := ftFloat;
  816. OFieldType := SQLT_BDOUBLE;
  817. OFieldSize := sizeof(double);
  818. end;
  819. SQLT_BLOB : begin
  820. FieldType := ftBlob;
  821. ODescType := OCI_DTYPE_LOB;
  822. end;
  823. SQLT_CLOB : begin
  824. FieldType := ftMemo;
  825. ODescType := OCI_DTYPE_LOB;
  826. end
  827. else
  828. FieldType := ftUnknown;
  829. end;
  830. FieldBuffers[counter-1].DescType := ODescType;
  831. if ODescType <> 0 then
  832. begin
  833. OBuffer := @FieldBuffers[counter-1].buffer;
  834. OCIDescriptorAlloc(FOciEnvironment, OBuffer, ODescType, 0, nil);
  835. OFieldSize := sizeof(pointer);
  836. end
  837. else
  838. begin
  839. OBuffer := getmem(OFieldSize);
  840. FieldBuffers[counter-1].buffer := OBuffer;
  841. end;
  842. if FieldType <> ftUnknown then
  843. begin
  844. FOciDefine := nil;
  845. if OciDefineByPos(FOciStmt,FOciDefine,FOciError,counter,OBuffer,OFieldSize,OFieldType,@FieldBuffers[counter-1].ind,nil,nil,OCI_DEFAULT) = OCI_ERROR then
  846. HandleError;
  847. end;
  848. if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldName,@OFNameLength,OCI_ATTR_NAME,FOciError) <> OCI_SUCCESS then
  849. HandleError;
  850. setlength(Fieldname,OFNameLength);
  851. move(OFieldName^,Fieldname[1],OFNameLength);
  852. FieldDefs.Add(FieldDefs.MakeNameUnique(FieldName), FieldType, FieldSize, False, counter);
  853. end;
  854. end;
  855. end;
  856. function TOracleConnection.Fetch(cursor: TSQLCursor): boolean;
  857. begin
  858. case OCIStmtFetch2((cursor as TOracleCursor).FOciStmt,FOciError,1,OCI_FETCH_NEXT,1,OCI_DEFAULT) of
  859. OCI_ERROR : begin
  860. Result := False;
  861. HandleError;
  862. end;
  863. OCI_NO_DATA : Result := False;
  864. OCI_SUCCESS : Result := True;
  865. OCI_SUCCESS_WITH_INFO : Begin
  866. Result := True;
  867. HandleError;
  868. end;
  869. end; {case}
  870. end;
  871. function TOracleConnection.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef; buffer: pointer; out CreateBlob : boolean): boolean;
  872. var
  873. b : pbyte;
  874. size,i : byte;
  875. exp : shortint;
  876. cur : Currency;
  877. odt : TODateTime;
  878. begin
  879. CreateBlob := False;
  880. with cursor as TOracleCursor do if fieldbuffers[FieldDef.FieldNo-1].ind = -1 then
  881. Result := False
  882. else
  883. begin
  884. Result := True;
  885. case FieldDef.DataType of
  886. ftString :
  887. move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,FieldDef.Size);
  888. ftBCD :
  889. begin
  890. b := fieldbuffers[FieldDef.FieldNo-1].buffer;
  891. size := b[0];
  892. cur := 0;
  893. if (b[1] and $80)=$80 then // the number is positive
  894. begin
  895. exp := (b[1] and $7f)-65;
  896. for i := 2 to size do
  897. cur := cur + (b[i]-1) * intpower(100,-(i-2)+exp);
  898. end
  899. else
  900. begin
  901. exp := (not(b[1]) and $7f)-65;
  902. for i := 2 to size-1 do
  903. cur := cur + (101-b[i]) * intpower(100,-(i-2)+exp);
  904. cur := -cur;
  905. end;
  906. move(cur,buffer^,SizeOf(Currency));
  907. end;
  908. ftFmtBCD :
  909. pBCD(buffer)^:= Nvu2FmtBCE(fieldbuffers[FieldDef.FieldNo-1].buffer);
  910. ftFloat :
  911. move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(double));
  912. ftSmallInt :
  913. move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(smallint));
  914. ftInteger :
  915. move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(integer));
  916. ftDate :
  917. begin
  918. b := fieldbuffers[FieldDef.FieldNo-1].buffer;
  919. PDateTime(buffer)^ := ComposeDateTime(EncodeDate((b[0]-100)*100+(b[1]-100),b[2],b[3]), EncodeTime(b[4]-1, b[5]-1, b[6]-1, 0));
  920. end;
  921. ftDateTime :
  922. begin
  923. OCIDateTimeGetDate(FOciUserSession, FOciError, FieldBuffers[FieldDef.FieldNo-1].buffer, @odt.year, @odt.month, @odt.day);
  924. OCIDateTimeGetTime(FOciUserSession, FOciError, FieldBuffers[FieldDef.FieldNo-1].buffer, @odt.hour, @odt.min, @odt.sec, @odt.fsec);
  925. PDateTime(buffer)^ := ComposeDateTime(EncodeDate(odt.year,odt.month,odt.day), EncodeTime(odt.hour,odt.min,odt.sec,odt.fsec div 1000000));
  926. end;
  927. ftBlob,
  928. ftMemo :
  929. CreateBlob := True;
  930. else
  931. Result := False;
  932. end;
  933. end;
  934. end;
  935. procedure TOracleConnection.LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
  936. var LobLocator: pointer;
  937. len: ub4;
  938. begin
  939. LobLocator := (cursor as TOracleCursor).FieldBuffers[FieldDef.FieldNo-1].Buffer;
  940. //if OCILobLocatorIsInit(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, LobLocator, @is_init) = OCI_ERROR then
  941. // HandleError;
  942. if OciLobGetLength(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, LobLocator, @len) = OCI_ERROR then
  943. HandleError;
  944. // Len - For character LOBs, it is the number of characters, for binary LOBs and BFILEs it is the number of bytes
  945. ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, len);
  946. ABlobBuf^.BlobBuffer^.Size := len;
  947. if OciLobRead(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, LobLocator, @len, 1, ABlobBuf^.BlobBuffer^.Buffer, len, nil, nil, 0, SQLCS_IMPLICIT) = OCI_ERROR then
  948. HandleError;
  949. end;
  950. procedure TOracleConnection.FreeFldBuffers(cursor: TSQLCursor);
  951. begin
  952. // inherited FreeFldBuffers(cursor);
  953. end;
  954. procedure TOracleConnection.UpdateIndexDefs(IndexDefs: TIndexDefs;
  955. TableName: string);
  956. var qry : TSQLQuery;
  957. begin
  958. if not assigned(Transaction) then
  959. DatabaseError(SErrConnTransactionnSet);
  960. // Get table name into canonical format
  961. if (length(TableName)>2) and (TableName[1]=ObjectQuote) and (TableName[length(TableName)]=ObjectQuote) then
  962. TableName := AnsiDequotedStr(TableName, ObjectQuote)
  963. else
  964. TableName := UpperCase(TableName); //ANSI SQL: the name of an identifier (such as table names) are implicitly converted to uppercase, unless double quotes are used when referring to the identifier.
  965. qry := tsqlquery.Create(nil);
  966. qry.transaction := Transaction;
  967. qry.database := Self;
  968. with qry do
  969. begin
  970. ReadOnly := True;
  971. sql.clear;
  972. sql.add('SELECT '+
  973. 'i.INDEX_NAME, '+
  974. 'c.COLUMN_NAME, '+
  975. 'p.CONSTRAINT_TYPE '+
  976. 'FROM ALL_INDEXES i, ALL_IND_COLUMNS c,ALL_CONSTRAINTS p '+
  977. 'WHERE '+
  978. 'i.OWNER=c.INDEX_OWNER AND '+
  979. 'i.INDEX_NAME=c.INDEX_NAME AND '+
  980. 'p.INDEX_NAME(+)=i.INDEX_NAME AND '+
  981. 'c.TABLE_NAME = ''' + TableName + ''' '+
  982. 'ORDER by i.INDEX_NAME,c.COLUMN_POSITION');
  983. open;
  984. end;
  985. while not qry.eof do with IndexDefs.AddIndexDef do
  986. begin
  987. Name := trim(qry.fields[0].asstring);
  988. Fields := trim(qry.Fields[1].asstring);
  989. If UpperCase(qry.fields[2].asstring)='P' then options := options + [ixPrimary];
  990. If UpperCase(qry.fields[2].asstring)='U' then options := options + [ixUnique];
  991. qry.next;
  992. while (name = qry.fields[0].asstring) and (not qry.eof) do
  993. begin
  994. Fields := Fields + ';' + trim(qry.Fields[2].asstring);
  995. qry.next;
  996. end;
  997. end;
  998. qry.close;
  999. qry.free;
  1000. end;
  1001. function TOracleConnection.GetSchemaInfoSQL(SchemaType: TSchemaType;
  1002. SchemaObjectName, SchemaPattern: string): string;
  1003. var
  1004. s : string;
  1005. begin
  1006. case SchemaType of
  1007. stTables : s := 'SELECT '+
  1008. '''' + DatabaseName + ''' as catalog_name, '+
  1009. 'sys_context( ''userenv'', ''current_schema'' ) as schema_name, '+
  1010. 'TABLE_NAME '+
  1011. 'FROM USER_CATALOG ' +
  1012. 'WHERE '+
  1013. 'TABLE_TYPE<>''SEQUENCE'' '+
  1014. 'ORDER BY TABLE_NAME';
  1015. stSysTables : s := 'SELECT '+
  1016. '''' + DatabaseName + ''' as catalog_name, '+
  1017. 'OWNER as schema_name, '+
  1018. 'TABLE_NAME '+
  1019. 'FROM ALL_CATALOG ' +
  1020. 'WHERE '+
  1021. 'TABLE_TYPE<>''SEQUENCE'' '+
  1022. 'ORDER BY TABLE_NAME';
  1023. stColumns : s := 'SELECT '+
  1024. 'COLUMN_NAME, '+
  1025. 'DATA_TYPE as column_datatype, '+
  1026. 'CHARACTER_SET_NAME, '+
  1027. 'NULLABLE as column_nullable, '+
  1028. 'DATA_LENGTH as column_length, '+
  1029. 'DATA_PRECISION as column_precision, '+
  1030. 'DATA_SCALE as column_scale '+
  1031. {DATA_DEFAULT is type LONG; no support for that in oracleconnection so removed this from query}
  1032. 'FROM ALL_TAB_COLUMNS '+
  1033. 'WHERE Upper(TABLE_NAME) = '''+UpperCase(SchemaObjectName)+''' '+
  1034. 'ORDER BY COLUMN_NAME';
  1035. // Columns of tables, views and clusters accessible to user; hidden columns are filtered out.
  1036. stProcedures : s := 'SELECT '+
  1037. 'case when PROCEDURE_NAME is null then OBJECT_NAME ELSE OBJECT_NAME || ''.'' || PROCEDURE_NAME end AS procedure_name '+
  1038. 'FROM USER_PROCEDURES ';
  1039. else
  1040. DatabaseError(SMetadataUnavailable)
  1041. end; {case}
  1042. result := s;
  1043. end;
  1044. constructor TOracleConnection.Create(AOwner: TComponent);
  1045. begin
  1046. inherited Create(AOwner);
  1047. FConnOptions := FConnOptions + [sqEscapeRepeat];
  1048. FUserMem := nil;
  1049. end;
  1050. { TOracleConnectionDef }
  1051. class function TOracleConnectionDef.TypeName: String;
  1052. begin
  1053. Result:='Oracle';
  1054. end;
  1055. class function TOracleConnectionDef.ConnectionClass: TSQLConnectionClass;
  1056. begin
  1057. Result:=TOracleConnection;
  1058. end;
  1059. class function TOracleConnectionDef.Description: String;
  1060. begin
  1061. Result:='Connect to an Oracle database directly via the client library';
  1062. end;
  1063. class function TOracleConnectionDef.DefaultLibraryName: String;
  1064. begin
  1065. {$IfDef LinkDynamically}
  1066. Result:=ocilib;
  1067. {$else}
  1068. Result:='';
  1069. {$endif}
  1070. end;
  1071. class function TOracleConnectionDef.LoadFunction: TLibraryLoadFunction;
  1072. begin
  1073. {$IfDef LinkDynamically}
  1074. Result:=@InitialiseOCI;
  1075. {$else}
  1076. Result:=Nil;
  1077. {$endif}
  1078. end;
  1079. class function TOracleConnectionDef.UnLoadFunction: TLibraryUnLoadFunction;
  1080. begin
  1081. {$IfDef LinkDynamically}
  1082. Result:=@ReleaseOCI;
  1083. {$else}
  1084. Result:=Nil;
  1085. {$endif}
  1086. end;
  1087. class function TOracleConnectionDef.LoadedLibraryName: string;
  1088. begin
  1089. {$IfDef LinkDynamically}
  1090. Result:=OCILoadedLibrary;
  1091. {$else}
  1092. Result:='';
  1093. {$endif}
  1094. end;
  1095. { TOracleTrans }
  1096. destructor TOracleTrans.Destroy();
  1097. begin
  1098. OCIHandleFree(FOciTrans,OCI_HTYPE_TRANS);
  1099. OCIHandleFree(FOciSvcCtx,OCI_HTYPE_SVCCTX);
  1100. inherited Destroy();
  1101. end;
  1102. initialization
  1103. RegisterConnection(TOracleConnectionDef);
  1104. finalization
  1105. UnRegisterConnection(TOracleConnectionDef);
  1106. end.