SaveBlobToFile (WIP)
This commit is contained in:
parent
8aac65cc81
commit
1ad24d3f71
@ -70,6 +70,14 @@
|
|||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#define SYSERROR() GetLastError()
|
||||||
|
#else
|
||||||
|
#include <errno.h>
|
||||||
|
#define SYSERROR() errno
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace Firebird;
|
using namespace Firebird;
|
||||||
|
|
||||||
|
|
||||||
@ -243,8 +251,7 @@ FB_UDR_EXECUTE_FUNCTION
|
|||||||
throw Firebird::FbException(status, statusVector);
|
throw Firebird::FbException(status, statusVector);
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
// This generates an unrecognised C++ exception, which is insufficient.
|
throw std::runtime_error("Error writing file to BLOB.");
|
||||||
throw std::runtime_error("Error writing stream to BLOB.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -267,7 +274,7 @@ engine udr;
|
|||||||
FB_UDR_BEGIN_FUNCTION(MFK_SaveBlobToFile)
|
FB_UDR_BEGIN_FUNCTION(MFK_SaveBlobToFile)
|
||||||
//BEGIN
|
//BEGIN
|
||||||
FB_UDR_MESSAGE(InMessage,
|
FB_UDR_MESSAGE(InMessage,
|
||||||
(FB_CHAR(8191), afilename)
|
(FB_VARCHAR(8191), afilename)
|
||||||
(FB_BLOB, ablob)
|
(FB_BLOB, ablob)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -277,7 +284,8 @@ FB_UDR_MESSAGE(OutMessage,
|
|||||||
|
|
||||||
AutoRelease<IAttachment> att;
|
AutoRelease<IAttachment> att;
|
||||||
AutoRelease<ITransaction> tra;
|
AutoRelease<ITransaction> tra;
|
||||||
AutoRelease<IBlob> Blob;
|
AutoRelease<IBlob> blob;
|
||||||
|
ISC_STATUS_ARRAY statusVector = {0};
|
||||||
|
|
||||||
|
|
||||||
FB_UDR_EXECUTE_FUNCTION
|
FB_UDR_EXECUTE_FUNCTION
|
||||||
@ -292,47 +300,68 @@ FB_UDR_EXECUTE_FUNCTION
|
|||||||
* DOC NOTE - We do not test for existence of the file here!
|
* DOC NOTE - We do not test for existence of the file here!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::fstream File ( in->afilename.str , std::fstream::out | std::fstream::binary | std::fstream::app );
|
std::ofstream FileWriter ( in->afilename.str , std::ofstream::binary );
|
||||||
if (! File.is_open()) {
|
if (! FileWriter.is_open()) {
|
||||||
out->result = -2;
|
out->resultNull = FB_TRUE;
|
||||||
|
// Convert system error to a negative value and assign to result
|
||||||
|
out->result = ( SYSERROR() * -1 );
|
||||||
|
// important to set this to false here otherwise the error code will
|
||||||
|
// be hidden and NULL returned to the firebird engine. This is because
|
||||||
|
// the test for out->resultNull has precedence.
|
||||||
|
if ( out->result < 0 ) {
|
||||||
|
out->resultNull = FB_FALSE;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Blob.reset(att->openBlob(status, tra, &in->ablob, 0, nullptr));
|
att.reset(context->getAttachment(status));
|
||||||
if (Blob == nullptr) {
|
tra.reset(context->getTransaction(status));
|
||||||
|
blob.reset(att->openBlob(status, tra, &in->ablob, 0, nullptr));
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (blob == nullptr) {
|
||||||
|
out->resultNull = FB_TRUE;
|
||||||
out->result = -1;
|
out->result = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::uint8_t> Buffer (MaxSegmentSize, 0);
|
||||||
std::vector<char> Buffer (MaxSegmentSize, 0);
|
|
||||||
|
|
||||||
unsigned BytesRead = 0;
|
unsigned BytesRead = 0;
|
||||||
|
|
||||||
for (bool Eof = false; !Eof; )
|
for (bool Eof = false; !Eof; )
|
||||||
{
|
{
|
||||||
switch (Blob->getSegment( status, MaxSegmentSize, Buffer.data(), &BytesRead))
|
switch ( blob->getSegment ( status, MaxSegmentSize, Buffer.data(), &BytesRead))
|
||||||
{
|
{
|
||||||
case IStatus::RESULT_OK:
|
case IStatus::RESULT_OK:
|
||||||
case IStatus::RESULT_SEGMENT:
|
case IStatus::RESULT_SEGMENT:
|
||||||
{
|
{
|
||||||
File.write( Buffer.data(), Buffer.size() );
|
FileWriter.write( (char *) Buffer.data(), Buffer.size() );
|
||||||
out->result += BytesRead;
|
out->result += BytesRead;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
Blob->close( status ); // will close interface
|
blob->close( status ); // will close interface
|
||||||
Blob.release();
|
blob->release();
|
||||||
Eof = true;
|
Eof = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If we have got this far then we have written the blob.
|
||||||
|
// out->resultNULL ***must*** be set to false or else the function will return NULL
|
||||||
|
out->resultNull = FB_FALSE;
|
||||||
Buffer.clear();
|
Buffer.clear();
|
||||||
File.close();
|
FileWriter.close();
|
||||||
|
}
|
||||||
|
catch ( const FbException& error )
|
||||||
|
{
|
||||||
|
throw Firebird::FbException(status, statusVector);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
throw std::runtime_error("Error writing BLOB to file.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,15 +20,33 @@ execute procedure load_blob(3);
|
|||||||
execute procedure load_blob(4);
|
execute procedure load_blob(4);
|
||||||
commit;
|
commit;
|
||||||
|
|
||||||
select cast ( description as varchar(32) ) as DESCRIPTION
|
select cast ( description as varchar(16) ) as DESCRIPTION
|
||||||
, file_type
|
, file_type
|
||||||
, cast (left(source_file,32) as varchar(32)) as source_file
|
, cast (left(source_file,32) as varchar(32)) as source_file
|
||||||
, source_status
|
, source_status
|
||||||
-- , source_bytes D_BIGINT
|
, cast (left(target_file,32) as varchar(32)) as target_file
|
||||||
-- , target_file D_PATH
|
, target_status
|
||||||
-- , target_status D_STATUS
|
, target_bytes
|
||||||
-- , target_bytes D_BIGINT
|
|
||||||
-- , the_blob D_BLOB
|
|
||||||
from test_blobs;
|
from test_blobs;
|
||||||
commit;
|
commit;
|
||||||
|
|
||||||
|
set term ^;
|
||||||
|
shell
|
||||||
|
mkdir --verbose /tmp/testudrkit
|
||||||
|
ls /tmp/testudrkit
|
||||||
|
^
|
||||||
|
set term ;^
|
||||||
|
|
||||||
|
execute procedure save_blob(1, '/tmp/testudrkit/fb.conf' );
|
||||||
|
execute procedure save_blob(2, '/tmp/testudrkit/fb.log' );
|
||||||
|
commit;
|
||||||
|
|
||||||
|
select cast ( description as varchar(16) ) as DESCRIPTION
|
||||||
|
, file_type
|
||||||
|
, cast (left(source_file,32) as varchar(32)) as source_file
|
||||||
|
, source_status
|
||||||
|
, cast (left(target_file,32) as varchar(32)) as target_file
|
||||||
|
, target_status
|
||||||
|
, cast (target_bytes as varchar(16) ) as target_bytes
|
||||||
|
from test_blobs;
|
||||||
|
commit;
|
||||||
|
@ -85,10 +85,39 @@ begin
|
|||||||
EXCEPTION E_BLOB_EXCEPTION 'Error updating test_blobs';
|
EXCEPTION E_BLOB_EXCEPTION 'Error updating test_blobs';
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end ^
|
||||||
|
|
||||||
|
set term ;^
|
||||||
|
|
||||||
|
|
||||||
|
set term ^;
|
||||||
|
create or alter procedure save_blob ( a_test_blob_id D_ID, atarget_file D_PATH ) sql security definer
|
||||||
|
as
|
||||||
|
declare theblob D_BLOB;
|
||||||
|
declare result D_BIGINT;
|
||||||
|
declare status D_STATUS;
|
||||||
|
begin
|
||||||
|
|
||||||
|
select the_blob from test_blobs where test_blobs_id = :a_test_blob_id into :theblob;
|
||||||
|
select SaveBlobToFile( :atarget_file, :theblob ) from rdb$database into :result;
|
||||||
|
|
||||||
|
if ( result >= 0 ) then
|
||||||
|
status = 'W';
|
||||||
|
else
|
||||||
|
status = 'F';
|
||||||
|
|
||||||
|
update test_blobs
|
||||||
|
set target_file = :atarget_file
|
||||||
|
, target_bytes = :result
|
||||||
|
, target_status = :status
|
||||||
|
where test_blobs_id = :a_test_blob_id;
|
||||||
|
when any do begin
|
||||||
|
EXCEPTION E_BLOB_EXCEPTION 'Error updating test_blobs';
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end ^
|
end ^
|
||||||
|
|
||||||
set term ;^
|
set term ;^
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user