mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-11 09:26:15 +02:00
fcl-db: oracle: adjust buffer for BLOBs, when reading CLOBs,NCLOBs. Bug #32377
git-svn-id: trunk@37184 -
This commit is contained in:
parent
55a0fd5121
commit
950082f371
@ -383,19 +383,24 @@ var
|
|||||||
ConnectString : string;
|
ConnectString : string;
|
||||||
TempServiceContext : POCISvcCtx;
|
TempServiceContext : POCISvcCtx;
|
||||||
IsConnected : boolean;
|
IsConnected : boolean;
|
||||||
|
CharSetId: ub2;
|
||||||
begin
|
begin
|
||||||
{$IfDef LinkDynamically}
|
{$IfDef LinkDynamically}
|
||||||
InitialiseOCI;
|
InitialiseOCI;
|
||||||
{$EndIf}
|
{$EndIf}
|
||||||
|
|
||||||
inherited DoInternalConnect;
|
inherited DoInternalConnect;
|
||||||
//todo: get rid of FUserMem, as it isn't used
|
//ToDo: get rid of FUserMem, as it isn't used
|
||||||
FUserMem := nil;
|
FUserMem := nil;
|
||||||
IsConnected := false;
|
IsConnected := false;
|
||||||
|
|
||||||
try
|
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
|
// Create environment handle
|
||||||
if OCIEnvCreate(FOciEnvironment,OCI_DEFAULT,nil,nil,nil,nil,0,FUserMem) <> OCI_SUCCESS then
|
if OCIEnvNlsCreate(FOciEnvironment,OCI_DEFAULT,nil,nil,nil,nil,0,FUserMem,CharSetId,CharSetId) <> OCI_SUCCESS then
|
||||||
DatabaseError(SErrEnvCreateFailed,self);
|
DatabaseError(SErrEnvCreateFailed,self);
|
||||||
// Create error handle
|
// Create error handle
|
||||||
if OciHandleAlloc(FOciEnvironment,FOciError,OCI_HTYPE_ERROR,0,FUserMem) <> OCI_SUCCESS then
|
if OciHandleAlloc(FOciEnvironment,FOciError,OCI_HTYPE_ERROR,0,FUserMem) <> OCI_SUCCESS then
|
||||||
@ -405,10 +410,10 @@ begin
|
|||||||
DatabaseError(SErrHandleAllocFailed,self);
|
DatabaseError(SErrHandleAllocFailed,self);
|
||||||
|
|
||||||
// Initialize server handle
|
// Initialize server handle
|
||||||
if hostname='' then
|
if HostName='' then
|
||||||
connectstring := databasename
|
ConnectString := DatabaseName
|
||||||
else
|
else
|
||||||
connectstring := '//'+hostname+'/'+databasename;
|
ConnectString := '//'+HostName+'/'+DatabaseName;
|
||||||
if OCIServerAttach(FOciServer,FOciError,@(ConnectString[1]),Length(ConnectString),OCI_DEFAULT) <> OCI_SUCCESS then
|
if OCIServerAttach(FOciServer,FOciError,@(ConnectString[1]),Length(ConnectString),OCI_DEFAULT) <> OCI_SUCCESS then
|
||||||
HandleError();
|
HandleError();
|
||||||
|
|
||||||
@ -453,7 +458,7 @@ begin
|
|||||||
if not IsConnected then
|
if not IsConnected then
|
||||||
begin
|
begin
|
||||||
if assigned(FOciServer) then
|
if assigned(FOciServer) then
|
||||||
OCIHandleFree(FOciServer,OCI_HTYPE_SERVER);
|
OCIHandleFree(FOciServer,OCI_HTYPE_SERVER);
|
||||||
if assigned(FOciError) then
|
if assigned(FOciError) then
|
||||||
OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
|
OCIHandleFree(FOciError,OCI_HTYPE_ERROR);
|
||||||
if assigned(FOciEnvironment) then
|
if assigned(FOciEnvironment) then
|
||||||
@ -1120,7 +1125,7 @@ end;
|
|||||||
procedure TOracleConnection.LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
|
procedure TOracleConnection.LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
|
||||||
var LobLocator: pointer;
|
var LobLocator: pointer;
|
||||||
LobCharSetForm: ub1;
|
LobCharSetForm: ub1;
|
||||||
LobLength: ub4;
|
LobLength, LobSize: ub4;
|
||||||
begin
|
begin
|
||||||
LobLocator := (cursor as TOracleCursor).FieldBuffers[FieldDef.FieldNo-1].Buffer;
|
LobLocator := (cursor as TOracleCursor).FieldBuffers[FieldDef.FieldNo-1].Buffer;
|
||||||
//if OCILobLocatorIsInit(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, LobLocator, @is_init) = OCI_ERROR then
|
//if OCILobLocatorIsInit(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, LobLocator, @is_init) = OCI_ERROR then
|
||||||
@ -1130,10 +1135,24 @@ begin
|
|||||||
HandleError;
|
HandleError;
|
||||||
if OCILobCharSetForm(FOciEnvironment, FOciError, LobLocator, @LobCharSetForm) = OCI_ERROR then
|
if OCILobCharSetForm(FOciEnvironment, FOciError, LobLocator, @LobCharSetForm) = OCI_ERROR then
|
||||||
HandleError;
|
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);
|
ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, LobLength);
|
||||||
ABlobBuf^.BlobBuffer^.Size := LobLength;
|
LobSize := 0;
|
||||||
if (LobLength > 0) and (OciLobRead(TOracleTrans(ATransaction.Handle).FOciSvcCtx, FOciError, LobLocator, @LobLength, 1, ABlobBuf^.BlobBuffer^.Buffer, LobLength, nil, nil, 0, LobCharSetForm) = OCI_ERROR) then
|
// 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;
|
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;
|
end;
|
||||||
|
|
||||||
procedure TOracleConnection.FreeFldBuffers(cursor: TSQLCursor);
|
procedure TOracleConnection.FreeFldBuffers(cursor: TSQLCursor);
|
||||||
|
@ -1403,7 +1403,7 @@ function TSQLConnection.GetConnectionCharSet: string;
|
|||||||
begin
|
begin
|
||||||
// default implementation returns user supplied FCharSet
|
// default implementation returns user supplied FCharSet
|
||||||
// (can be overriden by descendants, which are able retrieve current connection charset using client API)
|
// (can be overriden by descendants, which are able retrieve current connection charset using client API)
|
||||||
Result := FCharSet;
|
Result := LowerCase(FCharSet);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSQLConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
|
function TSQLConnection.RowsAffected(cursor: TSQLCursor): TRowsCount;
|
||||||
|
Loading…
Reference in New Issue
Block a user