12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340 |
- unit oracleconnection;
- {
- Copyright (c) 2006-2014 by Joost van der Sluis, FPC contributors
- Oracle RDBMS connector using the OCI protocol
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- **********************************************************************}
- {$mode objfpc}{$H+}
- {$Define LinkDynamically}
- interface
- uses
- Classes, SysUtils, db, dbconst, sqldb, bufdataset,
- {$IfDef LinkDynamically}
- ocidyn,
- {$ELSE}
- oci,
- {$ENDIF}
- oratypes;
- const
- DefaultTimeOut = 60;
- type
- EOraDatabaseError = class(ESQLDatabaseError)
- public
- property ORAErrorCode: integer read ErrorCode; deprecated 'Please use ErrorCode instead of ORAErrorCode'; // June 2014
- end;
- TOracleTrans = Class(TSQLHandle)
- protected
- FOciSvcCtx : POCISvcCtx;
- FOciTrans : POCITrans;
- FOciFlags : ub4;
- public
- destructor Destroy(); override;
- end;
-
- TOraFieldBuf = record
- DescType : ub4; // descriptor type
- Buffer : pointer;
- Ind : sb2; // indicator
- Len : ub4;
- Size : ub4;
- end;
- TOracleCursor = Class(TSQLCursor)
- protected
- FOciStmt : POCIStmt;
- FieldBuffers : array of TOraFieldBuf;
- ParamBuffers : array of TOraFieldBuf;
- end;
- { TOracleConnection }
- TOracleConnection = class (TSQLConnection)
- private
- FOciEnvironment : POciEnv;
- FOciError : POCIError;
- FOciServer : POCIServer;
- FOciUserSession : POCISession;
- FUserMem : pointer;
- procedure HandleError;
- procedure GetParameters(cursor : TSQLCursor; ATransaction : TSQLTransaction; AParams : TParams);
- procedure SetParameters(cursor : TSQLCursor; ATransaction : TSQLTransaction; AParams : TParams);
- protected
- // - Connect/disconnect
- procedure DoInternalConnect; override;
- procedure DoInternalDisconnect; override;
- // - Handle (de)allocation
- function AllocateCursorHandle:TSQLCursor; override;
- procedure DeAllocateCursorHandle(var cursor:TSQLCursor); override;
- function AllocateTransactionHandle:TSQLHandle; override;
- // - Statement handling
- procedure PrepareStatement(cursor:TSQLCursor; ATransaction:TSQLTransaction; buf:string; AParams:TParams); override;
- procedure UnPrepareStatement(cursor:TSQLCursor); override;
- // - Transaction handling
- procedure InternalStartDBTransaction(trans:TOracleTrans);
- function GetTransactionHandle(trans:TSQLHandle):pointer; override;
- function StartDBTransaction(trans:TSQLHandle; AParams:string):boolean; override;
- function Commit(trans:TSQLHandle):boolean; override;
- function Rollback(trans:TSQLHandle):boolean; override;
- procedure CommitRetaining(trans:TSQLHandle); override;
- procedure RollbackRetaining(trans:TSQLHandle); override;
- // - Statement execution
- procedure Execute(cursor:TSQLCursor; ATransaction:TSQLTransaction; AParams:TParams); override;
- function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
- // - Result retrieval
- procedure AddFieldDefs(cursor:TSQLCursor; FieldDefs:TFieldDefs); override;
- function Fetch(cursor:TSQLCursor):boolean; override;
- function LoadField(cursor:TSQLCursor; FieldDef:TFieldDef; buffer:pointer; out CreateBlob : boolean):boolean; override;
- procedure LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction); override;
- procedure FreeFldBuffers(cursor:TSQLCursor); override;
- procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); override;
- function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; override;
- public
- constructor Create(AOwner : TComponent); override;
- end;
- { TOracleConnectionDef }
- TOracleConnectionDef = Class(TConnectionDef)
- Class Function TypeName : String; override;
- Class Function ConnectionClass : TSQLConnectionClass; override;
- Class Function Description : String; override;
- Class Function DefaultLibraryName : String; override;
- Class Function LoadFunction : TLibraryLoadFunction; override;
- Class Function UnLoadFunction : TLibraryUnLoadFunction; override;
- Class Function LoadedLibraryName: string; override;
- end;
- implementation
- uses
- math, StrUtils, FmtBCD;
- const
- ObjectQuote='"'; //beginning and ending quote for objects such as table names. Note: can be different from quotes around field names
- ResourceString
- SErrEnvCreateFailed = 'The creation of an Oracle environment failed.';
- SErrHandleAllocFailed = 'The allocation of the error handle failed.';
- SErrOracle = 'Oracle returned error %s:';
- type
- TODateTime = record
- year : sb2;
- month : ub1;
- day : ub1;
- hour : ub1;
- min : ub1;
- sec : ub1;
- fsec : ub4;
- end;
- // Callback functions
- function cbf_no_data(ictxp:Pdvoid; bindp:POCIBind; iter:ub4; index:ub4; bufpp:PPdvoid;
- alenp:Pub4; piecep:Pub1; indp:PPdvoid):sb4;cdecl;
- begin
- bufpp^ := nil;
- alenp^ := 0;
- indp^ := nil;
- piecep^ := OCI_ONE_PIECE;
- result:=OCI_CONTINUE;
- end;
- function cbf_get_data(octxp:Pdvoid; bindp:POCIBind; iter:ub4; index:ub4; bufpp:PPdvoid;
- alenp:PPub4; piecep:Pub1; indp:PPdvoid; rcodep:PPub2):sb4;cdecl;
- begin
- // Only 1 row can be stored. No support for multiple rows: only the last row is kept.
- bufpp^:=TOraFieldBuf(octxp^).Buffer;
- indp^ := @TOraFieldBuf(octxp^).Ind;
- TOraFieldBuf(octxp^).Len:=TOraFieldBuf(octxp^).Size; //reset size to full buffer
- alenp^ := @TOraFieldBuf(octxp^).Len;
- rcodep^:=nil;
- piecep^ := OCI_ONE_PIECE;
- result:=OCI_CONTINUE;
- end;
- // Conversions
- Procedure FmtBCD2Nvu(bcd:tBCD;b:pByte);
- var
- i,j,cnt : integer;
- nibbles : array [0..maxfmtbcdfractionsize-1] of byte;
- exp : shortint;
- bb : byte;
- begin
- fillchar(b[0],22,#0);
- if BCDPrecision(bcd)=0 then // zero, special case
- begin
- b[0]:=1;
- b[1]:=$80;
- end
- else
- begin
- if (BCDPrecision(bcd)-BCDScale(bcd)) mod 2 <>0 then // odd number before decimal point
- begin
- nibbles[0]:=0;
- j:=1;
- end
- else
- j:=0;
- for i:=0 to bcd.Precision -1 do
- if i mod 2 =0 then
- nibbles[i+j]:=bcd.Fraction[i div 2] shr 4
- else
- nibbles[i+j]:=bcd.Fraction[i div 2] and $0f;
- nibbles[bcd.Precision+j]:=0; // make sure last nibble is also 0 in case we have odd scale
- exp:=(BCDPrecision(bcd)-BCDScale(bcd)+1) div 2;
- cnt:=exp+(BCDScale(bcd)+1) div 2;
- // to avoid "ora 01438: value larger than specified precision allowed for this column"
- // remove trailing zeros (scale < 0)...
- while (nibbles[cnt*2-2]*10+nibbles[cnt*2-1])=0 do
- cnt:=cnt-1;
- // ... and remove leading zeros (scale > precision)
- j:=0;
- while (nibbles[j*2]*10+nibbles[j*2+1])=0 do
- begin
- j:=j+1;
- exp:=exp-1;
- end;
- if IsBCDNegative(bcd) then
- begin
- b[0]:=cnt-j+1;
- b[1]:=not(exp+64) and $7f ;
- for i:=j to cnt-1 do
- begin
- bb:=nibbles[i*2]*10+nibbles[i*2+1];
- b[2+i-j]:=101-bb;
- end;
- if 2+cnt-j<22 then // add a 102 at the end of the number if place left.
- begin
- b[0]:=b[0]+1;
- b[2+cnt-j]:=102;
- end;
- end
- else
- begin
- b[0]:=cnt-j+1;
- b[1]:=(exp+64) or $80 ;
- for i:=j to cnt-1 do
- begin
- bb:=nibbles[i*2]*10+nibbles[i*2+1];
- b[2+i-j]:=1+bb;
- end;
- end;
- end;
- end;
- function Nvu2FmtBCD(b:pbyte):tBCD;
- var
- i,j : integer;
- bb,size : byte;
- exp : shortint;
- nibbles : array [0..maxfmtbcdfractionsize-1] of byte;
- scale : integer;
- begin
- size := b[0];
- if (size=1) and (b[1]=$80) then // special representation for 0
- result:=IntegerToBCD(0)
- else
- begin
- result.SignSpecialPlaces:=0; //sign positive, non blank, scale 0
- result.Precision:=1; //BCDNegate works only if Precision <>0
- if (b[1] and $80)=$80 then // then the number is positive
- begin
- exp := (b[1] and $7f)-65;
- for i := 0 to size-2 do
- begin
- bb := b[i+2]-1;
- nibbles[i*2]:=bb div 10;
- nibbles[i*2+1]:=(bb mod 10);
- end;
- end
- else
- begin
- BCDNegate(result);
- exp := (not(b[1]) and $7f)-65;
- if b[size]=102 then // last byte doesn't count if = 102
- size:=size-1;
- for i := 0 to size-2 do
- begin
- bb := 101-b[i+2];
- nibbles[i*2]:=bb div 10;
- nibbles[i*2+1]:=(bb mod 10);
- end;
- end;
- nibbles[(size-1)*2]:=0;
- result.Precision:=(size-1)*2;
- scale:=result.Precision-(exp*2+2);
- if scale>=0 then
- begin
- if (scale>result.Precision) then // need to add leading 0s
- begin
- for i:=0 to (scale-result.Precision+1) div 2 do
- result.Fraction[i]:=0;
- i:=scale-result.Precision;
- result.Precision:=scale;
- end
- else
- i:=0;
- j:=i;
- if (i=0) and (nibbles[0]=0) then // get rid of leading zero received from oci
- begin
- result.Precision:=result.Precision-1;
- j:=-1;
- end;
- while i<=result.Precision do // copy nibbles
- begin
- if i mod 2 =0 then
- result.Fraction[i div 2]:=nibbles[i-j] shl 4
- else
- result.Fraction[i div 2]:=result.Fraction[i div 2] or nibbles[i-j];
- i:=i+1;
- end;
- result.SignSpecialPlaces:=result.SignSpecialPlaces or scale;
- end
- else
- begin // add trailing zeroes, increase precision to take them into account
- i:=0;
- while i<=result.Precision do // copy nibbles
- begin
- if i mod 2 =0 then
- result.Fraction[i div 2]:=nibbles[i] shl 4
- else
- result.Fraction[i div 2]:=result.Fraction[i div 2] or nibbles[i];
- i:=i+1;
- end;
- result.Precision:=result.Precision-scale;
- for i := size -1 to High(result.Fraction) do
- result.Fraction[i] := 0;
- end;
- end;
- end;
- // TOracleConnection
- procedure TOracleConnection.HandleError;
- var
- errcode : sb4;
- buf : array[0..1023] of char;
- begin
- OCIErrorGet(FOciError,1,nil,errcode,@buf[0],1024,OCI_HTYPE_ERROR);
- raise EOraDatabaseError.CreateFmt(pchar(buf), [], Self, errcode, '')
- end;
- procedure TOracleConnection.GetParameters(cursor: TSQLCursor; ATransaction : TSQLTransaction; AParams: TParams);
- var
- i : integer;
- odt : TODateTime;
- s : string;
- begin
- with cursor as TOracleCursor do for i := 0 to High(ParamBuffers) do
- with AParams[i] do
- if ParamType=ptOutput then
- begin
- if ParamBuffers[i].ind = -1 then
- Value:=null;
- case DataType of
- ftInteger : AsInteger := PInteger(ParamBuffers[i].buffer)^;
- ftFloat : AsFloat := PDouble(ParamBuffers[i].buffer)^;
- ftString : begin
- SetLength(s,ParamBuffers[i].Len);
- move(ParamBuffers[i].buffer^,s[1],length(s)+1);
- AsString:=s;
- end;
- ftDate, ftDateTime: begin
- OCIDateTimeGetDate(FOciUserSession, FOciError, ParamBuffers[i].buffer, @odt.year, @odt.month, @odt.day);
- OCIDateTimeGetTime(FOciUserSession, FOciError, ParamBuffers[i].buffer, @odt.hour, @odt.min, @odt.sec, @odt.fsec);
- AsDateTime := ComposeDateTime(EncodeDate(odt.year,odt.month,odt.day), EncodeTime(odt.hour,odt.min,odt.sec,odt.fsec div 1000000));
- end;
- ftFMTBcd : begin
- AsFMTBCD:=Nvu2FmtBCD(ParamBuffers[i].buffer);
- end;
- end;
- end;
- end;
- procedure TOracleConnection.DoInternalConnect;
- var
- ConnectString : string;
- TempServiceContext : POCISvcCtx;
- IsConnected : boolean;
- CharSetId: ub2;
- begin
- {$IfDef LinkDynamically}
- InitialiseOCI;
- {$EndIf}
- inherited DoInternalConnect;
- //ToDo: get rid of FUserMem, as it isn't used
- FUserMem := nil;
- IsConnected := false;
- try
- case GetConnectionCharSet of
- 'utf8': CharSetId := 873;
- else CharSetId := 0; // if it is 0, the NLS_LANG and NLS_NCHAR environment variables are used
- end;
- // Create environment handle
- if OCIEnvNlsCreate(FOciEnvironment,OCI_DEFAULT,nil,nil,nil,nil,0,FUserMem,CharSetId,CharSetId) <> OCI_SUCCESS then
- DatabaseError(SErrEnvCreateFailed,self);
- // Create error handle
- if OciHandleAlloc(FOciEnvironment,FOciError,OCI_HTYPE_ERROR,0,FUserMem) <> OCI_SUCCESS then
- DatabaseError(SErrHandleAllocFailed,self);
- // Create server handle
- if OciHandleAlloc(FOciEnvironment,FOciServer,OCI_HTYPE_SERVER,0,FUserMem) <> OCI_SUCCESS then
- DatabaseError(SErrHandleAllocFailed,self);
- // Initialize server handle
- if HostName='' then
- ConnectString := DatabaseName
- else
- ConnectString := '//'+HostName+'/'+DatabaseName;
- if OCIServerAttach(FOciServer,FOciError,@(ConnectString[1]),Length(ConnectString),OCI_DEFAULT) <> OCI_SUCCESS then
- HandleError();
- try
- // Create temporary service-context handle for user authentication
- if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
- DatabaseError(SErrHandleAllocFailed,self);
- try
- // Create user-session handle
- if OciHandleAlloc(FOciEnvironment,FOciUserSession,OCI_HTYPE_SESSION,0,FUserMem) <> OCI_SUCCESS then
- DatabaseError(SErrHandleAllocFailed,self);
- try
- // Set the server-handle in the service-context handle
- if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
- HandleError();
- // Set username and password in the user-session handle
- if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.UserName[1]),Length(Self.UserName),OCI_ATTR_USERNAME,FOciError) <> OCI_SUCCESS then
- HandleError();
- if OCIAttrSet(FOciUserSession,OCI_HTYPE_SESSION,@(Self.Password[1]),Length(Self.Password),OCI_ATTR_PASSWORD,FOciError) <> OCI_SUCCESS then
- HandleError();
- // Authenticate
- if OCISessionBegin(TempServiceContext,FOciError,FOcIUserSession,OCI_CRED_RDBMS,OCI_DEFAULT) <> OCI_SUCCESS then
- HandleError();
- IsConnected := true;
- finally
- if not IsConnected then
- begin
- OCIHandleFree(FOciUserSession,OCI_HTYPE_SESSION);
- FOciUserSession := nil;
- end;
- end;
- finally
- // Free temporary service-context handle
- OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
- end;
- finally
- if not IsConnected then
- OCIServerDetach(FOciServer,FOciError,OCI_DEFAULT);
- end;
- finally
- if not IsConnected then
- begin
- if assigned(FOciServer) then
- OCIHandleFree(FOciServer,OCI_HTYPE_SERVER);
- if assigned(FOciError) then
- OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
- if assigned(FOciEnvironment) then
- OCIHandleFree(FOciEnvironment,OCI_HTYPE_ENV);
- FOciEnvironment := nil;
- FOciError := nil;
- FOciServer := nil;
- end;
- end;
- end;
- procedure TOracleConnection.DoInternalDisconnect;
- var
- TempServiceContext : POCISvcCtx;
- begin
- inherited DoInternalDisconnect;
- if assigned(FOciEnvironment) then
- begin
- if assigned(FOciError) then
- begin
- if assigned(FOciServer) then
- begin
- if assigned(FOciUserSession) then
- begin
- try
- // Create temporary service-context handle for user-disconnect
- if OciHandleAlloc(FOciEnvironment,TempServiceContext,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
- DatabaseError(SErrHandleAllocFailed,self);
- // Set the server handle in the service-context handle
- if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
- HandleError();
- // Set the user session handle in the service-context handle
- if OCIAttrSet(TempServiceContext,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then
- HandleError();
- // Disconnect uses-session handle
- if OCISessionEnd(TempServiceContext,FOciError,FOcIUserSession,OCI_DEFAULT) <> OCI_SUCCESS then
- HandleError();
- finally
- // Free user-session handle
- OCIHandleFree(FOciUserSession,OCI_HTYPE_SESSION);
- // Free temporary service-context handle
- OCIHandleFree(TempServiceContext,OCI_HTYPE_SVCCTX);
- FOciUserSession := nil;
- end;
- end;
- try
- // Disconnect server handle
- if OCIServerDetach(FOciServer,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
- HandleError();
- finally
- // Free connection handles
- OCIHandleFree(FOciServer,OCI_HTYPE_SERVER);
- FOciServer := nil;
- end;
- end;
- OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
- FOciError := nil;
- end;
- OCIHandleFree(FOciEnvironment,OCI_HTYPE_ENV);
- FOciEnvironment := nil;
- end;
- {$IfDef LinkDynamically}
- ReleaseOCI;
- {$EndIf}
- end;
- function TOracleConnection.AllocateCursorHandle: TSQLCursor;
- var
- Cursor : TOracleCursor;
- begin
- Cursor:=TOracleCursor.Create;
- Result := cursor;
- end;
- procedure TOracleConnection.DeAllocateCursorHandle(var cursor: TSQLCursor);
- procedure FreeOraFieldBuffers(b: array of TOraFieldBuf);
- var i : integer;
- begin
- if Length(b) > 0 then
- for i := low(b) to high(b) do
- if b[i].DescType <> 0 then
- OciDescriptorFree(b[i].buffer, b[i].DescType)
- else
- freemem(b[i].buffer);
- end;
- begin
- with cursor as TOracleCursor do
- begin
- FreeOraFieldBuffers(FieldBuffers);
- FreeOraFieldBuffers(ParamBuffers);
- end;
- FreeAndNil(cursor);
- end;
- function TOracleConnection.AllocateTransactionHandle: TSQLHandle;
- var
- locRes : TOracleTrans;
- begin
- locRes := TOracleTrans.Create();
- try
- // Allocate service-context handle
- if OciHandleAlloc(FOciEnvironment,locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,0,FUserMem) <> OCI_SUCCESS then
- DatabaseError(SErrHandleAllocFailed,self);
- // Set the server-handle in the service-context handle
- if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,FOciServer,0,OCI_ATTR_SERVER,FOciError) <> OCI_SUCCESS then
- HandleError();
- // Set the user-session handle in the service-context handle
- if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,FOciUserSession,0,OCI_ATTR_SESSION,FOciError) <> OCI_SUCCESS then
- HandleError();
- // Allocate transaction handle
- if OciHandleAlloc(FOciEnvironment,locRes.FOciTrans,OCI_HTYPE_TRANS,0,FUserMem) <> OCI_SUCCESS then
- DatabaseError(SErrHandleAllocFailed,self);
- // Set the transaction handle in the service-context handle
- if OCIAttrSet(locRes.FOciSvcCtx,OCI_HTYPE_SVCCTX,locRes.FOciTrans,0,OCI_ATTR_TRANS,FOciError) <> OCI_SUCCESS then
- HandleError();
- except
- locRes.Free();
- raise;
- end;
- Result := locRes;
- end;
- procedure TOracleConnection.PrepareStatement(cursor: TSQLCursor;
- ATransaction: TSQLTransaction; buf: string; AParams: TParams);
-
- var i : integer;
- FOcibind : POCIDefine;
-
- OFieldType : ub2;
- OFieldSize : sb4;
- ODescType : ub4;
- OBuffer : pointer;
- stmttype : ub2;
- begin
- with cursor as TOracleCursor do
- begin
- if LogEvent(detActualSQL) then
- Log(detActualSQL,Buf);
- if OCIStmtPrepare2(TOracleTrans(ATransaction.Handle).FOciSvcCtx,FOciStmt,FOciError,@buf[1],length(buf),nil,0,OCI_NTV_SYNTAX,OCI_DEFAULT) = OCI_ERROR then
- HandleError;
- // Get statement type
- if OCIAttrGet(FOciStmt,OCI_HTYPE_STMT,@stmttype,nil,OCI_ATTR_STMT_TYPE,FOciError) = OCI_ERROR then
- HandleError;
- case stmttype of
- OCI_STMT_SELECT: FStatementType := stSelect;
- OCI_STMT_UPDATE: FStatementType := stUpdate;
- OCI_STMT_DELETE: FStatementType := stDelete;
- OCI_STMT_INSERT: FStatementType := stInsert;
- OCI_STMT_CREATE,
- OCI_STMT_DROP,
- OCI_STMT_DECLARE,
- OCI_STMT_ALTER: FStatementType := stDDL;
- else
- FStatementType := stUnknown;
- end;
- if FStatementType in [stUpdate,stDelete,stInsert,stDDL] then
- FSelectable:=false;
- if assigned(AParams) then
- begin
- setlength(ParamBuffers,AParams.Count);
- for i := 0 to AParams.Count-1 do
- begin
- ODescType := 0;
- case AParams[i].DataType of
- ftSmallInt, ftInteger :
- begin OFieldType := SQLT_INT; OFieldSize := sizeof(integer); end;
- ftLargeInt :
- begin OFieldType := SQLT_INT; OFieldSize := sizeof(int64); end;
- ftFloat :
- begin OFieldType := SQLT_FLT; OFieldSize := sizeof(double); end;
- ftDate, ftDateTime :
- begin OFieldType := SQLT_TIMESTAMP; OFieldSize := sizeof(pointer); ODescType := OCI_DTYPE_TIMESTAMP; end;
- ftFixedChar, ftString :
- begin OFieldType := SQLT_STR; OFieldSize := 4000; end;
- ftFMTBcd, ftBCD :
- begin OFieldType := SQLT_VNU; OFieldSize := 22; end;
- ftBlob :
- //begin OFieldType := SQLT_LVB; OFieldSize := 65535; end;
- begin OFieldType := SQLT_BLOB; OFieldSize := sizeof(pointer); ODescType := OCI_DTYPE_LOB; end;
- ftMemo :
- begin OFieldType := SQLT_LVC; OFieldSize := 65535; end;
- else
- DatabaseErrorFmt(SUnsupportedParameter,[Fieldtypenames[AParams[i].DataType]],self);
- end;
- ParamBuffers[i].DescType := ODescType;
- ParamBuffers[i].Len := OFieldSize;
- ParamBuffers[i].Size := OFieldSize;
- if ODescType <> 0 then
- begin
- OBuffer := @ParamBuffers[i].buffer;
- OCIDescriptorAlloc(FOciEnvironment, OBuffer, ODescType, 0, nil);
- end
- else
- begin
- OBuffer := getmem(OFieldSize);
- ParamBuffers[i].buffer := OBuffer;
- end;
- FOciBind := nil;
- if AParams[i].ParamType=ptInput then
- begin
- 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
- HandleError;
- end
- else if AParams[i].ParamType=ptOutput then
- begin
- 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
- HandleError;
- if OCIBindDynamic(FOcibind, FOciError, nil, @cbf_no_data, @parambuffers[i], @cbf_get_data) <> OCI_SUCCESS then
- HandleError;
- end;
- end;
- end;
- FPrepared := True;
- end;
- end;
- procedure TOracleConnection.SetParameters(cursor : TSQLCursor; ATransaction : TSQLTransaction; AParams : TParams);
- var i : integer;
- year, month, day, hour, min, sec, msec : word;
- s : string;
- LobBuffer : TBytes;
- LobLength : ub4;
- begin
- with cursor as TOracleCursor do for i := 0 to High(ParamBuffers) do with AParams[i] do
- if ParamType=ptInput then
- begin
- if IsNull then ParamBuffers[i].ind := -1 else ParamBuffers[i].ind := 0;
- case DataType of
- ftSmallInt,
- ftInteger : PInteger(ParamBuffers[i].buffer)^ := AsInteger;
- ftLargeInt : PInt64(ParamBuffers[i].buffer)^ := AsLargeInt;
- ftFloat : PDouble(ParamBuffers[i].buffer)^ := AsFloat;
- ftString,
- ftFixedChar : begin
- s := asString+#0;
- move(s[1],parambuffers[i].buffer^,length(s)+1);
- end;
- ftDate, ftDateTime: begin
- DecodeDate(asDateTime,year,month,day);
- DecodeTime(asDateTime,hour,min,sec,msec);
- if OCIDateTimeConstruct(FOciUserSession, FOciError, ParamBuffers[i].buffer, year, month, day, hour, min, sec, msec*1000000, nil, 0) = OCI_ERROR then
- HandleError;
- { pb := ParamBuffers[i].buffer;
- pb[0] := (year div 100)+100;
- pb[1] := (year mod 100)+100;
- pb[2] := month;
- pb[3] := day;
- pb[4] := hour+1;
- pb[5] := minute+1;
- pb[6] := second+1;
- }
- end;
- ftFmtBCD, ftBCD : begin
- FmtBCD2Nvu(asFmtBCD,parambuffers[i].buffer);
- end;
- ftBlob : begin
- LobBuffer := AsBlob; // todo: use AsBytes
- LobLength := length(LobBuffer);
- // create empty temporary LOB with zero length
- if OciLobCreateTemporary(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, ParamBuffers[i].Buffer, OCI_DEFAULT, OCI_DEFAULT, OCI_TEMP_BLOB, False, OCI_DURATION_SESSION) = OCI_ERROR then
- HandleError;
- if (LobLength > 0) and (OciLobWrite(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, ParamBuffers[i].Buffer, @LobLength, 1, @LobBuffer[0], LobLength, OCI_ONE_PIECE, nil, nil, 0, SQLCS_IMPLICIT) = OCI_ERROR) then
- HandleError;
- end;
- ftMemo : begin
- LobBuffer := AsBytes;
- LobLength := length(LobBuffer);
- if LobLength > 65531 then LobLength := 65531;
- PInteger(ParamBuffers[i].Buffer)^ := LobLength;
- Move(LobBuffer[0], (ParamBuffers[i].Buffer+sizeof(integer))^, LobLength);
- end;
- else
- DatabaseErrorFmt(SUnsupportedParameter,[DataType],self);
- end;
- end;
- end;
- procedure TOracleConnection.UnPrepareStatement(cursor: TSQLCursor);
- begin
- if OCIStmtRelease(TOracleCursor(cursor).FOciStmt,FOciError,nil,0,OCI_DEFAULT)<> OCI_SUCCESS then
- HandleError();
- cursor.FPrepared:=False;
- end;
- procedure TOracleConnection.InternalStartDBTransaction(trans : TOracleTrans);
- begin
- if OCITransStart(trans.FOciSvcCtx,FOciError,DefaultTimeOut,trans.FOciFlags) <> OCI_SUCCESS then
- HandleError();
- end;
- function TOracleConnection.GetTransactionHandle(trans: TSQLHandle): pointer;
- begin
- Result := trans;
- end;
- function TOracleConnection.StartDBTransaction(trans: TSQLHandle; AParams: string): boolean;
- var
- flags : ub4;
- i : Integer;
- s : string;
- locTrans : TOracleTrans;
- begin
- flags := OCI_TRANS_READWRITE;
- if AParams <> '' then begin
- i := 1;
- s := ExtractSubStr(AParams,i,StdWordDelims);
- while ( s <> '' ) do begin
- if ( s = 'readonly' ) then
- flags := OCI_TRANS_READONLY
- else if ( s = 'serializable' ) then
- flags := OCI_TRANS_SERIALIZABLE
- else if ( s = 'readwrite' ) then
- flags := OCI_TRANS_READWRITE;
- s := ExtractSubStr(AParams,i,StdWordDelims);
- end;
- end;
- locTrans := TOracleTrans(trans);
- locTrans.FOciFlags := flags or OCI_TRANS_NEW;
- InternalStartDBTransaction(locTrans);
- Result := True;
- end;
- function TOracleConnection.Commit(trans: TSQLHandle): boolean;
- begin
- if OCITransCommit(TOracleTrans(trans).FOciSvcCtx,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
- HandleError();
- Result := True;
- end;
- function TOracleConnection.Rollback(trans: TSQLHandle): boolean;
- begin
- if OCITransRollback(TOracleTrans(trans).FOciSvcCtx,FOciError,OCI_DEFAULT) <> OCI_SUCCESS then
- HandleError();
- Result := True;
- end;
- procedure TOracleConnection.CommitRetaining(trans: TSQLHandle);
- begin
- Commit(trans);
- InternalStartDBTransaction(TOracleTrans(trans));
- end;
- procedure TOracleConnection.RollbackRetaining(trans: TSQLHandle);
- begin
- Rollback(trans);
- InternalStartDBTransaction(TOracleTrans(trans));
- end;
- procedure TOracleConnection.Execute(cursor: TSQLCursor; ATransaction: TSQLTransaction; AParams: TParams);
- procedure FreeParameters;
- var i: integer;
- begin
- with cursor as TOracleCursor do
- for i:=0 to high(ParamBuffers) do
- if ParamBuffers[i].DescType = OCI_DTYPE_LOB then
- if OciLobFreeTemporary(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, ParamBuffers[i].Buffer) = OCI_ERROR then
- HandleError;
- end;
- begin
- if Assigned(AParams) and (AParams.Count > 0) then SetParameters(cursor, ATransaction, AParams);
- if LogEvent(detParamValue) then
- LogParams(AParams);
- if cursor.FStatementType = stSelect then
- begin
- if OCIStmtExecute(TOracleTrans(ATransaction.Handle).FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,0,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
- HandleError;
- end
- else
- begin
- if OCIStmtExecute(TOracleTrans(ATransaction.Handle).FOciSvcCtx,(cursor as TOracleCursor).FOciStmt,FOciError,1,0,nil,nil,OCI_DEFAULT) = OCI_ERROR then
- HandleError;
- if Assigned(AParams) and (AParams.Count > 0) then GetParameters(cursor, ATransaction, AParams);
- end;
- FreeParameters;
- end;
- function TOracleConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
- var rowcount: ub4;
- begin
- if Assigned(cursor) and (OCIAttrGet((cursor as TOracleCursor).FOciStmt, OCI_HTYPE_STMT, @rowcount, nil, OCI_ATTR_ROW_COUNT, FOciError) = OCI_SUCCESS) then
- Result:=rowcount
- else
- Result:=inherited RowsAffected(cursor);
- end;
- procedure TOracleConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TFieldDefs);
- var Param : POCIParam;
- counter : ub4;
- FieldType : TFieldType;
- FieldName : string;
- FieldSize : cardinal;
- OFieldType : ub2;
- OFieldName : Pchar;
- OFieldSize : ub4;
- OFNameLength : ub4;
- NumCols : ub4;
- FOciDefine : POCIDefine;
- OPrecision : sb2;
- OScale : sb1;
- ODescType : ub4;
- OBuffer : pointer;
- begin
- Param := nil;
- with cursor as TOracleCursor do
- begin
- if OCIAttrGet(FOciStmt,OCI_HTYPE_STMT,@numcols,nil,OCI_ATTR_PARAM_COUNT,FOciError) = OCI_ERROR then
- HandleError;
- // Note: needs to be cleared then allocated in one go.
- Setlength(FieldBuffers,numcols);
- for counter := 1 to numcols do
- begin
- // Clear OFieldSize. Oracle 9i, 10g doc says *ub4 but some clients use *ub2 leaving
- // high 16 bit untouched resulting in huge values and ORA-01062
- // WARNING: this does not work on big endian systems !!!!
- // To be tested if BE systems have this *ub2<->*ub4 problem
- OFieldSize:=0;
- ODescType :=0;
- if OCIParamGet(FOciStmt,OCI_HTYPE_STMT,FOciError,Param,counter) = OCI_ERROR then
- HandleError;
- if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldType,nil,OCI_ATTR_DATA_TYPE,FOciError) = OCI_ERROR then
- HandleError;
- if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldSize,nil,OCI_ATTR_DATA_SIZE,FOciError) = OCI_ERROR then
- HandleError;
- FieldSize := 0;
-
- case OFieldType of
- OCI_TYPECODE_NUMBER : begin
- if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oprecision,nil,OCI_ATTR_PRECISION,FOciError) = OCI_ERROR then
- HandleError;
- if OCIAttrGet(Param,OCI_DTYPE_PARAM,@Oscale,nil,OCI_ATTR_SCALE,FOciError) = OCI_ERROR then
- HandleError;
- if (Oscale = 0) and (Oprecision < 10) then
- begin
- if Oprecision=0 then //Number(0,0) = number(32,4)
- begin
- FieldType := ftFMTBCD;
- FieldSize := 4;
- OFieldType := SQLT_VNU;
- OFieldSize:= 22;
- end
- else if Oprecision < 5 then
- begin
- FieldType := ftSmallint;
- OFieldType := SQLT_INT;
- OFieldSize := sizeof(smallint);
- end
- else // OPrecision=5..9, OScale=0
- begin
- FieldType := ftInteger;
- OFieldType := SQLT_INT;
- OFieldSize:= sizeof(integer);
- end;
- end
- else if (Oscale = -127) {and (OPrecision=0)} then
- begin
- FieldType := ftFloat;
- OFieldType := SQLT_FLT;
- OFieldSize:=sizeof(double);
- end
- else if (Oscale >=0) and (Oscale <=4) and (OPrecision<=12) then
- begin
- FieldType := ftBCD;
- FieldSize := oscale;
- OFieldType := SQLT_VNU;
- OFieldSize:= 22;
- end
- else if (OPrecision-Oscale<64) and (Oscale < 64) then // limited to 63 digits before or after decimal point
- begin
- FieldType := ftFMTBCD;
- FieldSize := oscale;
- OFieldType := SQLT_VNU;
- OFieldSize:= 22;
- end
- else // approximation with double, best we can do
- begin
- FieldType := ftFloat;
- OFieldType := SQLT_FLT;
- OFieldSize:=sizeof(double);
- end;
- end;
- SQLT_LNG : begin
- FieldType := ftString;
- FieldSize := MaxSmallint; // OFieldSize is zero for LONG data type
- OFieldSize:= MaxSmallint+1;
- OFieldType:=SQLT_STR;
- end;
- OCI_TYPECODE_CHAR,
- OCI_TYPECODE_VARCHAR,
- OCI_TYPECODE_VARCHAR2 : begin
- FieldType := ftString;
- FieldSize := OFieldSize;
- inc(OFieldSize);
- OFieldType:=SQLT_STR;
- end;
- OCI_TYPECODE_DATE : FieldType := ftDate;
- OCI_TYPECODE_TIMESTAMP,
- OCI_TYPECODE_TIMESTAMP_LTZ,
- OCI_TYPECODE_TIMESTAMP_TZ :
- begin
- FieldType := ftDateTime;
- OFieldType := SQLT_TIMESTAMP;
- ODescType := OCI_DTYPE_TIMESTAMP;
- end;
- OCI_TYPECODE_BFLOAT,
- OCI_TYPECODE_BDOUBLE : begin
- FieldType := ftFloat;
- OFieldType := SQLT_BDOUBLE;
- OFieldSize := sizeof(double);
- end;
- SQLT_BLOB : begin
- FieldType := ftBlob;
- ODescType := OCI_DTYPE_LOB;
- end;
- SQLT_CLOB : begin
- FieldType := ftMemo;
- ODescType := OCI_DTYPE_LOB;
- end
- else
- FieldType := ftUnknown;
- end;
- FieldBuffers[counter-1].DescType := ODescType;
- if ODescType <> 0 then
- begin
- OBuffer := @FieldBuffers[counter-1].buffer;
- OCIDescriptorAlloc(FOciEnvironment, OBuffer, ODescType, 0, nil);
- OFieldSize := sizeof(pointer);
- end
- else
- begin
- OBuffer := getmem(OFieldSize);
- FieldBuffers[counter-1].buffer := OBuffer;
- end;
- if FieldType <> ftUnknown then
- begin
- FOciDefine := nil;
- if OciDefineByPos(FOciStmt,FOciDefine,FOciError,counter,OBuffer,OFieldSize,OFieldType,@FieldBuffers[counter-1].ind,nil,nil,OCI_DEFAULT) = OCI_ERROR then
- HandleError;
- end;
- if OCIAttrGet(Param,OCI_DTYPE_PARAM,@OFieldName,@OFNameLength,OCI_ATTR_NAME,FOciError) <> OCI_SUCCESS then
- HandleError;
- setlength(Fieldname,OFNameLength);
- move(OFieldName^,Fieldname[1],OFNameLength);
- FieldDefs.Add(FieldDefs.MakeNameUnique(FieldName), FieldType, FieldSize, False, counter);
- end;
- end;
- end;
- function TOracleConnection.Fetch(cursor: TSQLCursor): boolean;
- begin
- case OCIStmtFetch2((cursor as TOracleCursor).FOciStmt,FOciError,1,OCI_FETCH_NEXT,1,OCI_DEFAULT) of
- OCI_ERROR : begin
- Result := False;
- HandleError;
- end;
- OCI_NO_DATA : Result := False;
- OCI_SUCCESS : Result := True;
- OCI_SUCCESS_WITH_INFO : Begin
- Result := True;
- HandleError;
- end;
- end; {case}
- end;
- function TOracleConnection.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef; buffer: pointer; out CreateBlob : boolean): boolean;
- var
- b : pbyte;
- size,i : byte;
- exp : shortint;
- cur : Currency;
- odt : TODateTime;
- begin
- CreateBlob := False;
- with cursor as TOracleCursor do if fieldbuffers[FieldDef.FieldNo-1].ind = -1 then
- Result := False
- else
- begin
- Result := True;
- case FieldDef.DataType of
- ftString :
- move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,FieldDef.Size);
- ftBCD :
- begin
- b := fieldbuffers[FieldDef.FieldNo-1].buffer;
- size := b[0];
- cur := 0;
- if (b[1] and $80)=$80 then // the number is positive
- begin
- exp := (b[1] and $7f)-65;
- for i := 2 to size do
- cur := cur + (b[i]-1) * intpower(100,-(i-2)+exp);
- end
- else
- begin
- exp := (not(b[1]) and $7f)-65;
- for i := 2 to size-1 do
- cur := cur + (101-b[i]) * intpower(100,-(i-2)+exp);
- cur := -cur;
- end;
- move(cur,buffer^,SizeOf(Currency));
- end;
- ftFmtBCD :
- pBCD(buffer)^:= Nvu2FmtBCD(fieldbuffers[FieldDef.FieldNo-1].buffer);
- ftFloat :
- move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(double));
- ftSmallInt :
- move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(smallint));
- ftInteger :
- move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(integer));
- ftDate :
- begin
- b := fieldbuffers[FieldDef.FieldNo-1].buffer;
- 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));
- end;
- ftDateTime :
- begin
- OCIDateTimeGetDate(FOciUserSession, FOciError, FieldBuffers[FieldDef.FieldNo-1].buffer, @odt.year, @odt.month, @odt.day);
- OCIDateTimeGetTime(FOciUserSession, FOciError, FieldBuffers[FieldDef.FieldNo-1].buffer, @odt.hour, @odt.min, @odt.sec, @odt.fsec);
- PDateTime(buffer)^ := ComposeDateTime(EncodeDate(odt.year,odt.month,odt.day), EncodeTime(odt.hour,odt.min,odt.sec,odt.fsec div 1000000));
- end;
- ftBlob,
- ftMemo :
- CreateBlob := True;
- else
- Result := False;
- end;
- end;
- end;
- procedure TOracleConnection.LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
- var LobLocator: pointer;
- LobCharSetForm: ub1;
- LobLength, LobSize: ub4;
- begin
- LobLocator := (cursor as TOracleCursor).FieldBuffers[FieldDef.FieldNo-1].Buffer;
- //if OCILobLocatorIsInit(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, LobLocator, @is_init) = OCI_ERROR then
- // HandleError;
- // For character LOBs, it is the number of characters, for binary LOBs and BFILEs it is the number of bytes
- if OciLobGetLength(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, LobLocator, @LobLength) = OCI_ERROR then
- HandleError;
- if OCILobCharSetForm(FOciEnvironment, FOciError, LobLocator, @LobCharSetForm) = OCI_ERROR then
- HandleError;
- // Adjust initial buffer size (in bytes), while LobLength can be in characters
- case LobCharSetForm of
- 0: ; // BLOB
- SQLCS_IMPLICIT, // CLOB
- SQLCS_NCHAR: // NCLOB
- LobLength := LobLength*4;
- end;
- ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, LobLength);
- LobSize := 0;
- // For CLOBs and NCLOBs the total amount of data which should be readed is on input in characters, but on output is in bytes if client character set is varying-width
- // The application must call OCILobRead() (in streamed mode) over and over again to read more pieces of the LOB until the OCI_NEED_DATA error code is not returned.
- // If the LOB is a BLOB, the csid and csfrm parameters are ignored.
- if (LobLength > 0) and (OciLobRead(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, LobLocator, @LobSize, 1, ABlobBuf^.BlobBuffer^.Buffer, LobLength, nil, nil, 0, LobCharSetForm) = OCI_ERROR) then
- HandleError;
- // Shrink initial buffer if needed (we assume that LobSize is in bytes, what is true for CLOB,NCLOB if client character set is varying-width, but if client character set is fixed-width then it is in characters)
- if LobSize <> LobLength then
- ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, LobSize);
- ABlobBuf^.BlobBuffer^.Size := LobSize;
- end;
- procedure TOracleConnection.FreeFldBuffers(cursor: TSQLCursor);
- begin
- // inherited FreeFldBuffers(cursor);
- end;
- procedure TOracleConnection.UpdateIndexDefs(IndexDefs: TIndexDefs;
- TableName: string);
- var qry : TSQLQuery;
- begin
- if not assigned(Transaction) then
- DatabaseError(SErrConnTransactionnSet);
- // Get table name into canonical format
- if (length(TableName)>2) and (TableName[1]=ObjectQuote) and (TableName[length(TableName)]=ObjectQuote) then
- TableName := AnsiDequotedStr(TableName, ObjectQuote)
- else
- 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.
- qry := tsqlquery.Create(nil);
- qry.transaction := Transaction;
- qry.database := Self;
- with qry do
- begin
- ReadOnly := True;
- sql.clear;
- sql.add('SELECT '+
- 'i.INDEX_NAME, '+
- 'c.COLUMN_NAME, '+
- 'p.CONSTRAINT_TYPE '+
- 'FROM ALL_INDEXES i, ALL_IND_COLUMNS c,ALL_CONSTRAINTS p '+
- 'WHERE '+
- 'i.OWNER=c.INDEX_OWNER AND '+
- 'i.INDEX_NAME=c.INDEX_NAME AND '+
- 'p.INDEX_NAME(+)=i.INDEX_NAME AND '+
- 'c.TABLE_NAME = ''' + TableName + ''' '+
- 'ORDER by i.INDEX_NAME,c.COLUMN_POSITION');
- open;
- end;
- while not qry.eof do with IndexDefs.AddIndexDef do
- begin
- Name := trim(qry.fields[0].asstring);
- Fields := trim(qry.Fields[1].asstring);
- If UpperCase(qry.fields[2].asstring)='P' then options := options + [ixPrimary];
- If UpperCase(qry.fields[2].asstring)='U' then options := options + [ixUnique];
- qry.next;
- while (name = qry.fields[0].asstring) and (not qry.eof) do
- begin
- Fields := Fields + ';' + trim(qry.Fields[1].asstring);
- qry.next;
- end;
- end;
- qry.close;
- qry.free;
- end;
- function TOracleConnection.GetSchemaInfoSQL(SchemaType: TSchemaType;
- SchemaObjectName, SchemaPattern: string): string;
- var
- s : string;
- begin
- case SchemaType of
- stTables : s := 'SELECT '+
- '''' + DatabaseName + ''' as catalog_name, '+
- 'sys_context( ''userenv'', ''current_schema'' ) as schema_name, '+
- 'TABLE_NAME,'+
- 'TABLE_TYPE '+
- 'FROM USER_CATALOG ' +
- 'WHERE '+
- 'TABLE_TYPE<>''SEQUENCE'' '+
- 'ORDER BY TABLE_NAME';
- stSysTables : s := 'SELECT '+
- '''' + DatabaseName + ''' as catalog_name, '+
- 'OWNER as schema_name, '+
- 'TABLE_NAME,'+
- 'TABLE_TYPE '+
- 'FROM ALL_CATALOG ' +
- 'WHERE '+
- 'TABLE_TYPE<>''SEQUENCE'' '+
- 'ORDER BY TABLE_NAME';
- stColumns : s := 'SELECT '+
- 'OWNER as schema_name, '+
- 'COLUMN_NAME, '+
- 'DATA_TYPE as column_datatype, '+
- 'CHARACTER_SET_NAME, '+
- 'NULLABLE as column_nullable, '+
- 'DATA_LENGTH as column_length, '+
- 'DATA_PRECISION as column_precision, '+
- 'DATA_SCALE as column_scale, '+
- 'DATA_DEFAULT as column_default '+
- 'FROM ALL_TAB_COLUMNS '+
- 'WHERE Upper(TABLE_NAME) = '''+UpperCase(SchemaObjectName)+''' '+
- 'ORDER BY COLUMN_NAME';
- // Columns of tables, views and clusters accessible to user; hidden columns are filtered out.
- stProcedures : s := 'SELECT '+
- 'case when PROCEDURE_NAME is null then OBJECT_NAME ELSE OBJECT_NAME || ''.'' || PROCEDURE_NAME end AS procedure_name '+
- 'FROM USER_PROCEDURES ';
- else
- DatabaseError(SMetadataUnavailable)
- end; {case}
- result := s;
- end;
- constructor TOracleConnection.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FConnOptions := FConnOptions + [sqEscapeRepeat];
- FOciEnvironment := nil;
- FOciError := nil;
- FOciServer := nil;
- FOciUserSession := nil;
- FUserMem := nil;
- end;
- { TOracleConnectionDef }
- class function TOracleConnectionDef.TypeName: String;
- begin
- Result:='Oracle';
- end;
- class function TOracleConnectionDef.ConnectionClass: TSQLConnectionClass;
- begin
- Result:=TOracleConnection;
- end;
- class function TOracleConnectionDef.Description: String;
- begin
- Result:='Connect to an Oracle database directly via the client library';
- end;
- class function TOracleConnectionDef.DefaultLibraryName: String;
- begin
- {$IfDef LinkDynamically}
- Result:=ocilib;
- {$else}
- Result:='';
- {$endif}
- end;
- class function TOracleConnectionDef.LoadFunction: TLibraryLoadFunction;
- begin
- {$IfDef LinkDynamically}
- Result:=@InitialiseOCI;
- {$else}
- Result:=Nil;
- {$endif}
- end;
- class function TOracleConnectionDef.UnLoadFunction: TLibraryUnLoadFunction;
- begin
- {$IfDef LinkDynamically}
- Result:=@ReleaseOCI;
- {$else}
- Result:=Nil;
- {$endif}
- end;
- class function TOracleConnectionDef.LoadedLibraryName: string;
- begin
- {$IfDef LinkDynamically}
- Result:=OCILoadedLibrary;
- {$else}
- Result:='';
- {$endif}
- end;
- { TOracleTrans }
- destructor TOracleTrans.Destroy();
- begin
- OCIHandleFree(FOciTrans,OCI_HTYPE_TRANS);
- OCIHandleFree(FOciSvcCtx,OCI_HTYPE_SVCCTX);
- inherited Destroy();
- end;
- initialization
- RegisterConnection(TOracleConnectionDef);
- finalization
- UnRegisterConnection(TOracleConnectionDef);
- end.
|