Commit 4b0dbab3 authored by Maciej Sobczak's avatar Maciej Sobczak

Added uniform offset for BLOB read/write operations.

parent c5e37d27
......@@ -556,10 +556,8 @@ The SOCI library provides also an interface for basic operations on large object
The following functions are provided in the `blob` interface, mimicking the file-like operations:
*`std::size_t get_len();`
*`std::size_t read(std::size_t offset, char *buf, std::size_t
toRead);`
*`std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite);`
*`std::size_t read_from_start(char * buf, std::size_t toRead, std::size_t offset = 0);`
*`std::size_t write_from_start(const char * buf, std::size_t toWrite, std::size_t offset = 0);`
*`std::size_t append(char const *buf, std::size_t toWrite);`
*`void trim(std::size_t newLen);`
......
......@@ -30,10 +30,24 @@ public:
~blob();
std::size_t get_len();
// offset is backend-specific
std::size_t read(std::size_t offset, char * buf, std::size_t toRead);
// offset starts from 0
std::size_t read_from_start(char * buf, std::size_t toRead,
std::size_t offset = 0);
// offset is backend-specific
std::size_t write(std::size_t offset, char const * buf,
std::size_t toWrite);
// offset starts from 0
std::size_t write_from_start(const char * buf, std::size_t toWrite,
std::size_t offset = 0);
std::size_t append(char const * buf, std::size_t toWrite);
void trim(std::size_t newLen);
details::blob_backend * get_backend() { return backEnd_; }
......
......@@ -265,11 +265,27 @@ struct oracle_blob_backend : details::blob_backend
~oracle_blob_backend();
virtual std::size_t get_len();
virtual std::size_t read(std::size_t offset, char *buf,
std::size_t toRead);
virtual std::size_t read_from_start(char * buf, std::size_t toRead,
std::size_t offset)
{
return read(offset + 1, buf, toRead);
}
virtual std::size_t write(std::size_t offset, char const *buf,
std::size_t toWrite);
virtual std::size_t write_from_start(const char * buf, std::size_t toWrite,
std::size_t offset)
{
return write(offset + 1, buf, toWrite);
}
virtual std::size_t append(char const *buf, std::size_t toWrite);
virtual void trim(std::size_t newLen);
oracle_session_backend &session_;
......
......@@ -329,11 +329,27 @@ struct postgresql_blob_backend : details::blob_backend
~postgresql_blob_backend();
virtual std::size_t get_len();
virtual std::size_t read(std::size_t offset, char * buf,
std::size_t toRead);
virtual std::size_t read_from_start(char * buf, std::size_t toRead,
std::size_t offset)
{
return read(offset, buf, toRead);
}
virtual std::size_t write(std::size_t offset, char const * buf,
std::size_t toWrite);
virtual std::size_t write_from_start(const char * buf, std::size_t toWrite,
std::size_t offset)
{
return write(offset, buf, toWrite);
}
virtual std::size_t append(char const * buf, std::size_t toWrite);
virtual void trim(std::size_t newLen);
postgresql_session_backend & session_;
......
......@@ -218,11 +218,27 @@ public:
virtual ~blob_backend() {}
virtual std::size_t get_len() = 0;
virtual std::size_t read(std::size_t offset, char* buf,
std::size_t toRead) = 0;
virtual std::size_t read_from_start(char * buf, std::size_t toRead,
std::size_t offset)
{
throw soci_error("read_from_start is not implemented for this backend");
}
virtual std::size_t write(std::size_t offset, char const* buf,
std::size_t toWrite) = 0;
virtual std::size_t write_from_start(const char * buf, std::size_t toWrite,
std::size_t offset)
{
throw soci_error("write_from_start is not implemented for this backend");
}
virtual std::size_t append(char const* buf, std::size_t toWrite) = 0;
virtual void trim(std::size_t newLen) = 0;
private:
......
......@@ -20,7 +20,12 @@ shared : generated ${OBJS}
${COMPILER} -shared -o libsoci_core.so ${OBJS}
rm *.o
generated : ../../include/private/soci_backends_config.h
generated : ../../include/soci/soci-config.h ../../include/private/soci_backends_config.h
# Note: this file is generated without any configured variables,
# full configuration fill is generated by CMake.
../../include/soci/soci-config.h : ../../include/soci/soci-config.h.in
grep -v CONFIGURED_VARIABLES $? > $@
# Note: this file is generated with a basic search path,
# full backends search path is generated by CMake.
......
......@@ -33,12 +33,24 @@ std::size_t blob::read(std::size_t offset, char *buf, std::size_t toRead)
return backEnd_->read(offset, buf, toRead);
}
std::size_t blob::read_from_start(char * buf, std::size_t toRead,
std::size_t offset)
{
return backEnd_->read_from_start(buf, toRead, offset);
}
std::size_t blob::write(
std::size_t offset, char const * buf, std::size_t toWrite)
{
return backEnd_->write(offset, buf, toWrite);
}
std::size_t blob::write_from_start(const char * buf, std::size_t toWrite,
std::size_t offset)
{
return backEnd_->write_from_start(buf, toWrite, offset);
}
std::size_t blob::append(char const * buf, std::size_t toWrite)
{
return backEnd_->append(buf, toWrite);
......
......@@ -118,48 +118,97 @@ struct blob_table_creator : public table_creator_base
TEST_CASE("Oracle blob", "[oracle][blob]")
{
soci::session sql(backEnd, connectString);
{
session sql(backEnd, connectString);
blob_table_creator tableCreator(sql);
blob_table_creator tableCreator(sql);
char buf[] = "abcdefghijklmnopqrstuvwxyz";
sql << "insert into soci_test (id, img) values (7, empty_blob())";
char buf[] = "abcdefghijklmnopqrstuvwxyz";
sql << "insert into soci_test (id, img) values (7, empty_blob())";
{
blob b(sql);
{
blob b(sql);
oracle_session_backend *sessionBackEnd
= static_cast<oracle_session_backend *>(sql.get_backend());
oracle_session_backend *sessionBackEnd
= static_cast<oracle_session_backend *>(sql.get_backend());
oracle_blob_backend *blobBackEnd
= static_cast<oracle_blob_backend *>(b.get_backend());
oracle_blob_backend *blobBackEnd
= static_cast<oracle_blob_backend *>(b.get_backend());
OCILobDisableBuffering(sessionBackEnd->svchp_,
sessionBackEnd->errhp_, blobBackEnd->lobp_);
OCILobDisableBuffering(sessionBackEnd->svchp_,
sessionBackEnd->errhp_, blobBackEnd->lobp_);
sql << "select img from soci_test where id = 7", into(b);
CHECK(b.get_len() == 0);
sql << "select img from soci_test where id = 7", into(b);
CHECK(b.get_len() == 0);
// note: blob offsets start from 1
b.write(1, buf, sizeof(buf));
CHECK(b.get_len() == sizeof(buf));
b.trim(10);
CHECK(b.get_len() == 10);
// note: blob offsets start from 1
b.write(1, buf, sizeof(buf));
CHECK(b.get_len() == sizeof(buf));
b.trim(10);
CHECK(b.get_len() == 10);
// append does not work (Oracle bug #886191 ?)
//b.append(buf, sizeof(buf));
//assert(b.get_len() == sizeof(buf) + 10);
sql.commit();
}
// append does not work (Oracle bug #886191 ?)
//b.append(buf, sizeof(buf));
//CHECK(b.get_len() == sizeof(buf) + 10);
sql.commit();
{
blob b(sql);
sql << "select img from soci_test where id = 7", into(b);
//assert(b.get_len() == sizeof(buf) + 10);
CHECK(b.get_len() == 10);
char buf2[100];
b.read(1, buf2, 10);
CHECK(strncmp(buf2, "abcdefghij", 10) == 0);
}
}
// additional sibling test for read_from_start and write_from_start
{
blob b(sql);
sql << "select img from soci_test where id = 7", into(b);
//CHECK(b.get_len() == sizeof(buf) + 10);
CHECK(b.get_len() == 10);
char buf2[100];
b.read(1, buf2, 10);
CHECK(strncmp(buf2, "abcdefghij", 10) == 0);
session sql(backEnd, connectString);
blob_table_creator tableCreator(sql);
char buf[] = "abcdefghijklmnopqrstuvwxyz";
sql << "insert into soci_test (id, img) values (7, empty_blob())";
{
blob b(sql);
oracle_session_backend *sessionBackEnd
= static_cast<oracle_session_backend *>(sql.get_backend());
oracle_blob_backend *blobBackEnd
= static_cast<oracle_blob_backend *>(b.get_backend());
OCILobDisableBuffering(sessionBackEnd->svchp_,
sessionBackEnd->errhp_, blobBackEnd->lobp_);
sql << "select img from soci_test where id = 7", into(b);
CHECK(b.get_len() == 0);
// note: blob offsets start from 1
b.write_from_start(buf, sizeof(buf));
CHECK(b.get_len() == sizeof(buf));
b.trim(10);
CHECK(b.get_len() == 10);
// append does not work (Oracle bug #886191 ?)
//b.append(buf, sizeof(buf));
//assert(b.get_len() == sizeof(buf) + 10);
sql.commit();
}
{
blob b(sql);
sql << "select img from soci_test where id = 7", into(b);
//assert(b.get_len() == sizeof(buf) + 10);
CHECK(b.get_len() == 10);
char buf2[100];
b.read_from_start(buf2, 10);
CHECK(strncmp(buf2, "abcdefghij", 10) == 0);
}
}
}
......
......@@ -195,41 +195,82 @@ struct blob_table_creator : public table_creator_base
TEST_CASE("PostgreSQL blob", "[postgresql][blob]")
{
soci::session sql(backEnd, connectString);
{
session sql(backEnd, connectString);
blob_table_creator tableCreator(sql);
blob_table_creator tableCreator(sql);
char buf[] = "abcdefghijklmnopqrstuvwxyz";
char buf[] = "abcdefghijklmnopqrstuvwxyz";
sql << "insert into soci_test(id, img) values(7, lo_creat(-1))";
sql << "insert into soci_test(id, img) values(7, lo_creat(-1))";
// in PostgreSQL, BLOB operations must be within transaction block
transaction tr(sql);
// in PostgreSQL, BLOB operations must be within transaction block
transaction tr(sql);
{
blob b(sql);
{
blob b(sql);
sql << "select img from soci_test where id = 7", into(b);
CHECK(b.get_len() == 0);
sql << "select img from soci_test where id = 7", into(b);
CHECK(b.get_len() == 0);
b.write(0, buf, sizeof(buf));
CHECK(b.get_len() == sizeof(buf));
b.write(0, buf, sizeof(buf));
CHECK(b.get_len() == sizeof(buf));
b.append(buf, sizeof(buf));
CHECK(b.get_len() == 2 * sizeof(buf));
}
{
blob b(sql);
sql << "select img from soci_test where id = 7", into(b);
CHECK(b.get_len() == 2 * sizeof(buf));
char buf2[100];
b.read(0, buf2, 10);
CHECK(std::strncmp(buf2, "abcdefghij", 10) == 0);
}
b.append(buf, sizeof(buf));
CHECK(b.get_len() == 2 * sizeof(buf));
unsigned long oid;
sql << "select img from soci_test where id = 7", into(oid);
sql << "select lo_unlink(" << oid << ")";
}
// additional sibling test for read_from_start and write_from_start
{
blob b(sql);
sql << "select img from soci_test where id = 7", into(b);
CHECK(b.get_len() == 2 * sizeof(buf));
char buf2[100];
b.read(0, buf2, 10);
CHECK(std::strncmp(buf2, "abcdefghij", 10) == 0);
}
session sql(backEnd, connectString);
blob_table_creator tableCreator(sql);
char buf[] = "abcdefghijklmnopqrstuvwxyz";
unsigned long oid;
sql << "select img from soci_test where id = 7", into(oid);
sql << "select lo_unlink(" << oid << ")";
sql << "insert into soci_test(id, img) values(7, lo_creat(-1))";
// in PostgreSQL, BLOB operations must be within transaction block
transaction tr(sql);
{
blob b(sql);
sql << "select img from soci_test where id = 7", into(b);
CHECK(b.get_len() == 0);
b.write_from_start(buf, sizeof(buf));
CHECK(b.get_len() == sizeof(buf));
b.append(buf, sizeof(buf));
CHECK(b.get_len() == 2 * sizeof(buf));
}
{
blob b(sql);
sql << "select img from soci_test where id = 7", into(b);
CHECK(b.get_len() == 2 * sizeof(buf));
char buf2[100];
b.read_from_start(buf2, 10);
CHECK(std::strncmp(buf2, "abcdefghij", 10) == 0);
}
unsigned long oid;
sql << "select img from soci_test where id = 7", into(oid);
sql << "select lo_unlink(" << oid << ")";
}
}
struct longlong_table_creator : table_creator_base
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment