mirror of
https://github.com/SOCI/soci.git
synced 2026-05-02 09:09:39 -05:00
finalize common blob test & remove backend-specific ones
This commit is contained in:
+177
-79
@@ -6378,119 +6378,217 @@ TEST_CASE_METHOD(common_tests, "BLOB", "[core][blob]")
|
||||
|
||||
if (!tableCreator.get())
|
||||
{
|
||||
try
|
||||
{
|
||||
soci::blob blob(sql);
|
||||
FAIL("BLOB creation should throw, if backend doesn't support BLOBs");
|
||||
} catch (const soci_error &)
|
||||
{
|
||||
// Throwing is expected if the backend doesn't support BLOBs
|
||||
}
|
||||
try
|
||||
{
|
||||
soci::blob blob(sql);
|
||||
FAIL("BLOB creation should throw, if backend doesn't support BLOBs");
|
||||
} catch (const soci_error &)
|
||||
{
|
||||
// Throwing is expected if the backend doesn't support BLOBs
|
||||
}
|
||||
WARN("BLOB type not supported by the database, skipping the test.");
|
||||
return;
|
||||
}
|
||||
|
||||
const char dummy_data[] = "abcdefghijklmnopüqrstuvwxyz";
|
||||
const char dummy_data[] = "abcdefghijklmnopüqrstuvwxyz";
|
||||
|
||||
// Cross-DB usage of BLOBs is only possible if the entire lifetime of the blob object
|
||||
// is covered in an active transaction.
|
||||
soci::transaction transaction(sql);
|
||||
{
|
||||
SECTION("Read-access on default-constructed blob")
|
||||
{
|
||||
soci::blob blob(sql);
|
||||
// Cross-DB usage of BLOBs is only possible if the entire lifetime of the blob object
|
||||
// is covered in an active transaction.
|
||||
soci::transaction transaction(sql);
|
||||
{
|
||||
SECTION("Read-access on default-constructed blob")
|
||||
{
|
||||
soci::blob blob(sql);
|
||||
|
||||
CHECK(blob.get_len() == 0);
|
||||
CHECK(blob.get_len() == 0);
|
||||
|
||||
char buf[5];
|
||||
std::size_t read_bytes = blob.read_from_start(buf, sizeof(buf));
|
||||
char buf[5];
|
||||
std::size_t read_bytes = blob.read_from_start(buf, sizeof(buf));
|
||||
|
||||
// There should be no data that could be read
|
||||
CHECK(read_bytes == 0);
|
||||
// There should be no data that could be read
|
||||
CHECK(read_bytes == 0);
|
||||
|
||||
// Reading from any offset other than zero is invalid
|
||||
CHECK_THROWS_AS(blob.read_from_start(buf, sizeof(buf), 1), soci_error);
|
||||
}
|
||||
SECTION("Write-access on default-constructed blob")
|
||||
{
|
||||
soci::blob blob(sql);
|
||||
// Reading from any offset other than zero is invalid
|
||||
CHECK_THROWS_AS(blob.read_from_start(buf, sizeof(buf), 1), soci_error);
|
||||
}
|
||||
SECTION("BLOB I/O")
|
||||
{
|
||||
soci::blob blob(sql);
|
||||
|
||||
std::size_t written_bytes = blob.write_from_start(dummy_data, 5);
|
||||
std::size_t written_bytes = blob.write_from_start(dummy_data, 5);
|
||||
|
||||
CHECK(written_bytes == 5);
|
||||
CHECK(blob.get_len() == 5);
|
||||
CHECK(written_bytes == 5);
|
||||
CHECK(blob.get_len() == 5);
|
||||
|
||||
char buf[5];
|
||||
char buf[5];
|
||||
static_assert(sizeof(buf) <= sizeof(dummy_data), "Underlying assumption violated");
|
||||
|
||||
std::size_t read_bytes = blob.read_from_start(buf, sizeof(buf));
|
||||
std::size_t read_bytes = blob.read_from_start(buf, sizeof(buf));
|
||||
|
||||
CHECK(read_bytes == 5);
|
||||
CHECK(read_bytes == sizeof(buf));
|
||||
|
||||
for (std::size_t i = 0; i < sizeof(buf); ++i)
|
||||
{
|
||||
CHECK(buf[i] == dummy_data[i]);
|
||||
}
|
||||
for (std::size_t i = 0; i < sizeof(buf); ++i)
|
||||
{
|
||||
CHECK(buf[i] == dummy_data[i]);
|
||||
}
|
||||
|
||||
written_bytes = blob.append(dummy_data + 5, 3);
|
||||
written_bytes = blob.append(dummy_data + 5, 3);
|
||||
|
||||
CHECK(written_bytes == 3);
|
||||
CHECK(blob.get_len() == 8);
|
||||
CHECK(written_bytes == 3);
|
||||
CHECK(blob.get_len() == 8);
|
||||
|
||||
read_bytes = blob.read_from_start(buf, sizeof(buf), 3);
|
||||
read_bytes = blob.read_from_start(buf, sizeof(buf), 3);
|
||||
|
||||
CHECK(read_bytes == 5);
|
||||
CHECK(read_bytes == 5);
|
||||
|
||||
for (std::size_t i = 0; i < sizeof(buf); ++i)
|
||||
{
|
||||
CHECK(buf[i] == dummy_data[i + 3]);
|
||||
}
|
||||
for (std::size_t i = 0; i < sizeof(buf); ++i)
|
||||
{
|
||||
CHECK(buf[i] == dummy_data[i + 3]);
|
||||
}
|
||||
|
||||
blob.trim(2);
|
||||
blob.trim(2);
|
||||
|
||||
CHECK(blob.get_len() == 2);
|
||||
CHECK(blob.get_len() == 2);
|
||||
|
||||
read_bytes = blob.read_from_start(buf, sizeof(buf));
|
||||
read_bytes = blob.read_from_start(buf, sizeof(buf));
|
||||
|
||||
CHECK(read_bytes == 2);
|
||||
CHECK(read_bytes == 2);
|
||||
|
||||
for (std::size_t i = 0; i < read_bytes; ++i)
|
||||
{
|
||||
CHECK(buf[i] == dummy_data[i]);
|
||||
}
|
||||
for (std::size_t i = 0; i < read_bytes; ++i)
|
||||
{
|
||||
CHECK(buf[i] == dummy_data[i]);
|
||||
}
|
||||
|
||||
// Reading from an offset >= the current length of the blob is invalid
|
||||
CHECK_THROWS_AS(blob.read_from_start(buf, sizeof(buf), blob.get_len()), soci_error);
|
||||
// Reading from an offset >= the current length of the blob is invalid
|
||||
CHECK_THROWS_AS(blob.read_from_start(buf, sizeof(buf), blob.get_len()), soci_error);
|
||||
|
||||
written_bytes = blob.append("z", 1);
|
||||
|
||||
CHECK(written_bytes == 1);
|
||||
CHECK(blob.get_len() == 3);
|
||||
written_bytes = blob.append("z", 1);
|
||||
|
||||
CHECK(written_bytes == 1);
|
||||
CHECK(blob.get_len() == 3);
|
||||
|
||||
read_bytes = blob.read_from_start(buf, 1, 2);
|
||||
read_bytes = blob.read_from_start(buf, 1, 2);
|
||||
|
||||
CHECK(read_bytes == 1);
|
||||
CHECK(buf[0] == 'z');
|
||||
CHECK(read_bytes == 1);
|
||||
CHECK(buf[0] == 'z');
|
||||
|
||||
// Writing more than one position beyond the blob is invalid
|
||||
// (Writing exactly one position beyond is the same as appending)
|
||||
CHECK_THROWS_AS(blob.write_from_start(dummy_data, 2, blob.get_len() + 1), soci_error);
|
||||
}
|
||||
SECTION("Inserting/Reading default-constructed blob")
|
||||
{
|
||||
soci::blob input_blob(sql);
|
||||
// Writing more than one position beyond the blob is invalid
|
||||
// (Writing exactly one position beyond is the same as appending)
|
||||
CHECK_THROWS_AS(blob.write_from_start(dummy_data, 2, blob.get_len() + 1), soci_error);
|
||||
}
|
||||
SECTION("Inserting/Reading default-constructed blob")
|
||||
{
|
||||
soci::blob input_blob(sql);
|
||||
|
||||
sql << "insert into soci_test (id, b) values(5, :b)", soci::use(input_blob);
|
||||
sql << "insert into soci_test (id, b) values(5, :b)", soci::use(input_blob);
|
||||
|
||||
soci::blob output_blob(sql);
|
||||
soci::indicator ind;
|
||||
soci::blob output_blob(sql);
|
||||
soci::indicator ind;
|
||||
|
||||
sql << "select b from soci_test where id = 5", soci::into(output_blob, ind);
|
||||
sql << "select b from soci_test where id = 5", soci::into(output_blob, ind);
|
||||
|
||||
CHECK(ind == soci::i_ok);
|
||||
CHECK(output_blob.get_len() == 0);
|
||||
}
|
||||
}
|
||||
transaction.rollback();
|
||||
CHECK(ind == soci::i_ok);
|
||||
CHECK(output_blob.get_len() == 0);
|
||||
}
|
||||
SECTION("Ensure reading into blob overwrites previous contents")
|
||||
{
|
||||
soci::blob blob(sql);
|
||||
blob.write_from_start("hello kitty", 10);
|
||||
|
||||
CHECK(blob.get_len() == 10);
|
||||
|
||||
soci::blob write_blob(sql);
|
||||
write_blob.write_from_start("test", 4);
|
||||
sql << "insert into soci_test (id, b) values (5, :b)", soci::use(write_blob);
|
||||
|
||||
sql << "select b from soci_test where id = 5", soci::into(blob);
|
||||
|
||||
CHECK(blob.get_len() == 4);
|
||||
char buf[5];
|
||||
|
||||
std::size_t read_bytes = blob.read_from_start(buf, sizeof(buf));
|
||||
CHECK(read_bytes == 4);
|
||||
|
||||
CHECK(buf[0] == 't');
|
||||
CHECK(buf[1] == 'e');
|
||||
CHECK(buf[2] == 's');
|
||||
CHECK(buf[3] == 't');
|
||||
}
|
||||
SECTION("Blob-DB interaction")
|
||||
{
|
||||
soci::blob write_blob(sql);
|
||||
|
||||
static_assert(sizeof(dummy_data) >= 10, "Underlying assumption violated");
|
||||
write_blob.write_from_start(dummy_data, 10);
|
||||
|
||||
const int first_id = 42;
|
||||
|
||||
// Write and retrieve blob from/into database
|
||||
sql << "insert into soci_test (id, b) values(:id, :b)", soci::use(first_id), soci::use(write_blob);
|
||||
|
||||
soci::blob read_blob(sql);
|
||||
sql << "select b from soci_test where id = :id", soci::use(first_id), soci::into(read_blob);
|
||||
CHECK(sql.got_data());
|
||||
|
||||
CHECK(read_blob.get_len() == write_blob.get_len());
|
||||
|
||||
char buf[15];
|
||||
std::size_t bytes_read = read_blob.read_from_start(buf, sizeof(buf));
|
||||
CHECK(bytes_read == read_blob.get_len());
|
||||
CHECK(bytes_read == 10);
|
||||
for (std::size_t i = 0; i < bytes_read; ++i) {
|
||||
CHECK(buf[i] == dummy_data[i]);
|
||||
}
|
||||
|
||||
// Update original blob and insert new db-entry (must not change previous entry)
|
||||
const int second_id = first_id + 1;
|
||||
write_blob.trim(0);
|
||||
static_assert(sizeof(dummy_data) >= 15 + 5, "Underlying assumption violated");
|
||||
write_blob.write_from_start(dummy_data + 15, 5);
|
||||
|
||||
sql << "insert into soci_test (id, b) values (:id, :b)", soci::use(second_id), soci::use(write_blob);
|
||||
|
||||
// First, check that the original entry has not been changed
|
||||
sql << "select b from soci_test where id = :id", soci::use(first_id), soci::into(read_blob);
|
||||
CHECK(read_blob.get_len() == 10);
|
||||
|
||||
// Then check new entry can be read
|
||||
sql << "select b from soci_test where id = :id", soci::use(second_id), soci::into(read_blob);
|
||||
|
||||
bytes_read = read_blob.read_from_start(buf, sizeof(buf));
|
||||
CHECK(bytes_read == read_blob.get_len());
|
||||
CHECK(bytes_read == 5);
|
||||
for (std::size_t i = 0; i < bytes_read; ++i) {
|
||||
CHECK(buf[i] == dummy_data[i + 15]);
|
||||
}
|
||||
}
|
||||
SECTION("Binary data")
|
||||
{
|
||||
const std::uint8_t binary_data[12] = {0, 1, 2, 3, 4, 5, 6, 7, 22, 255, 250 };
|
||||
|
||||
soci::blob write_blob(sql);
|
||||
|
||||
std::size_t bytes_written = write_blob.write_from_start(reinterpret_cast<const char *>(binary_data), sizeof(binary_data));
|
||||
CHECK(bytes_written == sizeof(binary_data));
|
||||
|
||||
sql << "insert into soci_test (id, b) values (1, :b)", soci::use(write_blob);
|
||||
|
||||
soci::blob read_blob(sql);
|
||||
|
||||
sql << "select b from soci_test where id = 1", soci::into(read_blob);
|
||||
|
||||
CHECK(read_blob.get_len() == sizeof(binary_data));
|
||||
|
||||
std::uint8_t buf[20];
|
||||
std::size_t bytes_read = read_blob.read_from_start(reinterpret_cast<char *>(buf), sizeof(buf));
|
||||
|
||||
CHECK(bytes_read == sizeof(binary_data));
|
||||
for (std::size_t i = 0; i < sizeof(binary_data); ++i) {
|
||||
CHECK(buf[i] == binary_data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
transaction.rollback();
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(common_tests, "Logger", "[core][log]")
|
||||
|
||||
@@ -500,152 +500,6 @@ TEST_CASE("Firebird bulk operations", "[firebird][bulk]")
|
||||
sql << "drop table test6";
|
||||
}
|
||||
|
||||
// blob test
|
||||
TEST_CASE("Firebird blobs", "[firebird][blob]")
|
||||
{
|
||||
soci::session sql(backEnd, connectString);
|
||||
|
||||
try
|
||||
{
|
||||
sql << "drop table test7";
|
||||
}
|
||||
catch (std::runtime_error &)
|
||||
{} // ignore if error
|
||||
|
||||
sql << "create table test7(id integer, img blob)";
|
||||
sql.commit();
|
||||
|
||||
sql.begin();
|
||||
{
|
||||
// Read from default-constructed BLOB
|
||||
blob b(sql);
|
||||
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
char buf[5];
|
||||
std::size_t read = b.read_from_start(buf, 5);
|
||||
CHECK(read == 0);
|
||||
}
|
||||
{
|
||||
// verify empty blob
|
||||
blob b(sql);
|
||||
indicator ind;
|
||||
|
||||
sql << "insert into test7(id, img) values(1,?)", use(b);
|
||||
sql << "select img from test7 where id = 1", into(b, ind);
|
||||
|
||||
CHECK(ind == i_ok);
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
sql << "delete from test7";
|
||||
}
|
||||
|
||||
{
|
||||
// create a new blob
|
||||
blob b(sql);
|
||||
|
||||
char str1[] = "Hello";
|
||||
b.write_from_start(str1, strlen(str1));
|
||||
|
||||
char str2[20];
|
||||
std::size_t i = b.read_from_start(str2, 2, 3);
|
||||
str2[i] = '\0';
|
||||
CHECK(str2[0] == 'l');
|
||||
CHECK(str2[1] == 'o');
|
||||
CHECK(str2[2] == '\0');
|
||||
|
||||
char str3[] = ", Firebird!";
|
||||
b.append(str3, strlen(str3));
|
||||
|
||||
sql << "insert into test7(id, img) values(1,?)", use(b);
|
||||
}
|
||||
|
||||
{
|
||||
// read & update blob
|
||||
blob b(sql);
|
||||
|
||||
sql << "select img from test7 where id = 1", into(b);
|
||||
|
||||
std::vector<char> text(b.get_len());
|
||||
b.read_from_start(&text[0], b.get_len());
|
||||
CHECK(strncmp(&text[0], "Hello, Firebird!", b.get_len()) == 0);
|
||||
|
||||
char str1[] = "FIREBIRD";
|
||||
b.write_from_start(str1, strlen(str1), 7);
|
||||
|
||||
// after modification blob must be written to database
|
||||
sql << "update test7 set img=? where id=1", use(b);
|
||||
}
|
||||
|
||||
{
|
||||
// read blob from database, modify and write to another record
|
||||
blob b(sql);
|
||||
|
||||
sql << "select img from test7 where id = 1", into(b);
|
||||
|
||||
std::vector<char> text(b.get_len());
|
||||
b.read_from_start(&text[0], b.get_len());
|
||||
|
||||
char str1[] = "HELLO";
|
||||
b.write_from_start(str1, strlen(str1));
|
||||
|
||||
b.read_from_start(&text[0], b.get_len());
|
||||
CHECK(strncmp(&text[0], "HELLO, FIREBIRD!", b.get_len()) == 0);
|
||||
|
||||
b.trim(5);
|
||||
sql << "insert into test7(id, img) values(2,?)", use(b);
|
||||
}
|
||||
|
||||
{
|
||||
blob b(sql);
|
||||
statement st = (sql.prepare << "select img from test7", into(b));
|
||||
|
||||
st.execute();
|
||||
|
||||
st.fetch();
|
||||
std::vector<char> text(b.get_len());
|
||||
b.read_from_start(&text[0], b.get_len());
|
||||
CHECK(strncmp(&text[0], "Hello, FIREBIRD!", b.get_len()) == 0);
|
||||
|
||||
st.fetch();
|
||||
text.resize(b.get_len());
|
||||
b.read_from_start(&text[0], b.get_len());
|
||||
CHECK(strncmp(&text[0], "HELLO", b.get_len()) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
// delete blob
|
||||
blob b(sql);
|
||||
indicator ind=i_null;
|
||||
sql << "update test7 set img=? where id = 1", use(b, ind);
|
||||
|
||||
sql << "select img from test7 where id = 2", into(b, ind);
|
||||
CHECK(ind==i_ok);
|
||||
|
||||
sql << "select img from test7 where id = 1", into(b, ind);
|
||||
CHECK(ind==i_null);
|
||||
}
|
||||
|
||||
{
|
||||
//create large blob
|
||||
const int blobSize = 65536; //max segment size is 65535(unsigned short)
|
||||
std::vector<char> data(blobSize);
|
||||
blob b(sql);
|
||||
b.write_from_start(data.data(), blobSize);
|
||||
sql << "insert into test7(id, img) values(3,?)", use(b);
|
||||
|
||||
//now read blob back from database and make sure it has correct content and size
|
||||
blob br(sql);
|
||||
sql << "select img from test7 where id = 3", into(br);
|
||||
std::vector<char> data2(br.get_len());
|
||||
if(br.get_len()>0)
|
||||
br.read_from_start(data2.data(), br.get_len());
|
||||
CHECK(data == data2);
|
||||
}
|
||||
|
||||
sql << "drop table test7";
|
||||
}
|
||||
|
||||
// named parameters
|
||||
TEST_CASE("Firebird named parameters", "[firebird][named-params]")
|
||||
{
|
||||
|
||||
@@ -605,104 +605,6 @@ TEST_CASE("MySQL function call", "[mysql][function]")
|
||||
sql << "select concat(@day,' ',@mm,' ',@year)", into(r);
|
||||
}
|
||||
|
||||
// BLOB test
|
||||
struct blob_table_creator : public table_creator_base
|
||||
{
|
||||
blob_table_creator(soci::session & sql)
|
||||
: table_creator_base(sql)
|
||||
{
|
||||
sql <<
|
||||
"create table soci_test ("
|
||||
" id integer,"
|
||||
" img blob"
|
||||
")";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("MySQL blob", "[mysql][blob]")
|
||||
{
|
||||
soci::session sql(backEnd, connectString);
|
||||
|
||||
blob_table_creator tableCreator(sql);
|
||||
|
||||
const char buf[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
{
|
||||
// Read from default-constructed BLOB
|
||||
blob b(sql);
|
||||
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
char buf2[5];
|
||||
std::size_t read = b.read_from_start(buf2, 5);
|
||||
CHECK(read == 0);
|
||||
}
|
||||
{
|
||||
// empty, default-constructed BLOB
|
||||
blob b(sql);
|
||||
indicator ind;
|
||||
|
||||
sql << "insert into soci_test(id, img) values(1, :img)", use(b);
|
||||
sql << "select img from soci_test where id = 1", into(b, ind);
|
||||
|
||||
CHECK(ind == i_ok);
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
sql << "delete from soci_test where id = 1";
|
||||
}
|
||||
{
|
||||
// Create new BLOB
|
||||
blob b(sql);
|
||||
|
||||
b.write_from_start(buf, sizeof(buf));
|
||||
|
||||
char substr[20];
|
||||
std::size_t i = b.read_from_start(substr, 3);
|
||||
substr[i] = '\0';
|
||||
CHECK(substr[0] == buf[0]);
|
||||
CHECK(substr[1] == buf[1]);
|
||||
CHECK(substr[2] == buf[2]);
|
||||
CHECK(substr[3] == '\0');
|
||||
|
||||
sql << "insert into soci_test(id, img) values(7, :img)", use(b);
|
||||
}
|
||||
{
|
||||
// Append to BLOB
|
||||
blob b(sql);
|
||||
|
||||
sql << "select img from soci_test where id = 7", into(b);
|
||||
CHECK(b.get_len() == sizeof(buf));
|
||||
|
||||
b.append(buf, sizeof(buf));
|
||||
|
||||
CHECK(b.get_len() == 2 * sizeof(buf));
|
||||
|
||||
sql << "update soci_test set img = :img where id = 7", use(b);
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
{
|
||||
blob b(sql);
|
||||
sql << "select img from soci_test where id = 7", into(b);
|
||||
CHECK(b.get_len() == 2 * sizeof(buf));
|
||||
b.trim(sizeof(buf));
|
||||
CHECK(b.get_len() == sizeof(buf));
|
||||
|
||||
sql << "update soci_test set img = :img where id = 7", use(b);
|
||||
}
|
||||
{
|
||||
blob b(sql);
|
||||
sql << "select img from soci_test where id = 7", into(b);
|
||||
CHECK(b.get_len() == sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
struct double_value_table_creator : table_creator_base
|
||||
{
|
||||
double_value_table_creator(soci::session & sql)
|
||||
|
||||
@@ -52,7 +52,7 @@ struct table_creator_for_get_affected_rows : table_creator_base
|
||||
struct table_creator_for_blob : public tests::table_creator_base
|
||||
{
|
||||
table_creator_for_blob(soci::session & sql)
|
||||
: tests::table_creator_base(sql)
|
||||
: tests::table_creator_base(sql)
|
||||
{
|
||||
sql << "create table soci_test(id integer, b blob)";
|
||||
}
|
||||
|
||||
@@ -102,95 +102,7 @@ TEST_CASE("Oracle explicit calls", "[oracle]")
|
||||
CHECK(i == 7);
|
||||
}
|
||||
|
||||
// DDL + blob test
|
||||
|
||||
struct blob_table_creator : public table_creator_base
|
||||
{
|
||||
blob_table_creator(soci::session & sql)
|
||||
: table_creator_base(sql)
|
||||
{
|
||||
sql <<
|
||||
"create table soci_test ("
|
||||
" id number(10) not null,"
|
||||
" img blob"
|
||||
")";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Oracle blob", "[oracle][blob]")
|
||||
{
|
||||
soci::session sql(backEnd, connectString);
|
||||
|
||||
soci::transaction transaction(sql);
|
||||
|
||||
blob_table_creator tableCreator(sql);
|
||||
|
||||
char buf[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
sql << "insert into soci_test (id, img) values (7, empty_blob())";
|
||||
|
||||
{
|
||||
blob b(sql);
|
||||
|
||||
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);
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
{
|
||||
// Read from default-constructed BLOB
|
||||
blob b(sql);
|
||||
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
char buf[5];
|
||||
std::size_t read = b.read_from_start(buf, 5);
|
||||
CHECK(read == 0);
|
||||
}
|
||||
{
|
||||
// empty, default-constructed BLOB
|
||||
blob b(sql);
|
||||
indicator ind;
|
||||
|
||||
sql << "insert into soci_test(id, img) values(1, :img)", use(b);
|
||||
sql << "select img from soci_test where id = 1", into(b, ind);
|
||||
|
||||
CHECK(ind == i_ok);
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
sql << "delete from soci_test where id = 1";
|
||||
}
|
||||
{
|
||||
// Create new BLOB
|
||||
blob b(sql);
|
||||
|
||||
b.write_from_start(buf, sizeof(buf));
|
||||
|
||||
char substr[20];
|
||||
std::size_t i = b.read_from_start(substr, 3);
|
||||
substr[i] = '\0';
|
||||
CHECK(substr[0] == buf[0]);
|
||||
CHECK(substr[1] == buf[1]);
|
||||
CHECK(substr[2] == buf[2]);
|
||||
CHECK(substr[3] == '\0');
|
||||
|
||||
sql << "insert into soci_test(id, img) values(7, :img)", use(b);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
// DDL test
|
||||
|
||||
// nested statement test
|
||||
// (the same syntax is used for output cursors in PL/SQL)
|
||||
|
||||
@@ -229,110 +229,6 @@ TEST_CASE("PostgreSQL function call", "[postgresql][function]")
|
||||
}
|
||||
}
|
||||
|
||||
// BLOB test
|
||||
struct blob_table_creator : public table_creator_base
|
||||
{
|
||||
blob_table_creator(soci::session & sql)
|
||||
: table_creator_base(sql)
|
||||
{
|
||||
sql <<
|
||||
"create table soci_test ("
|
||||
" id integer,"
|
||||
" img oid"
|
||||
")";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("PostgreSQL blob", "[postgresql][blob]")
|
||||
{
|
||||
soci::session sql(backEnd, connectString);
|
||||
|
||||
blob_table_creator tableCreator(sql);
|
||||
|
||||
const char buf[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
// in PostgreSQL, BLOB operations must be within transaction block
|
||||
transaction tr(sql);
|
||||
|
||||
{
|
||||
// Read from default-constructed BLOB
|
||||
blob b(sql);
|
||||
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
char buf2[5];
|
||||
std::size_t read = b.read_from_start(buf2, 5);
|
||||
CHECK(read == 0);
|
||||
}
|
||||
{
|
||||
// empty, default-constructed BLOB
|
||||
blob b(sql);
|
||||
indicator ind;
|
||||
|
||||
sql << "insert into soci_test(id, img) values(1, :img)", use(b);
|
||||
sql << "select img from soci_test where id = 1", into(b, ind);
|
||||
|
||||
CHECK(ind == i_ok);
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
sql << "delete from soci_test where id = 1";
|
||||
}
|
||||
{
|
||||
// Create new BLOB
|
||||
blob b(sql);
|
||||
|
||||
b.write_from_start(buf, sizeof(buf));
|
||||
|
||||
char substr[20];
|
||||
std::size_t i = b.read_from_start(substr, 3);
|
||||
substr[i] = '\0';
|
||||
CHECK(substr[0] == buf[0]);
|
||||
CHECK(substr[1] == buf[1]);
|
||||
CHECK(substr[2] == buf[2]);
|
||||
CHECK(substr[3] == '\0');
|
||||
|
||||
sql << "insert into soci_test(id, img) values(7, :img)", use(b);
|
||||
}
|
||||
{
|
||||
// Append to BLOB
|
||||
blob b(sql);
|
||||
|
||||
sql << "select img from soci_test where id = 7", into(b);
|
||||
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);
|
||||
}
|
||||
#if PG_VERSION_NUM >= 80003
|
||||
{
|
||||
blob b(sql);
|
||||
sql << "select img from soci_test where id = 7", into(b);
|
||||
CHECK(b.get_len() == 2 * sizeof(buf));
|
||||
b.trim(sizeof(buf));
|
||||
CHECK(b.get_len() == sizeof(buf));
|
||||
}
|
||||
{
|
||||
blob b(sql);
|
||||
sql << "select img from soci_test where id = 7", into(b);
|
||||
CHECK(b.get_len() == sizeof(buf));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Destroy BLOB
|
||||
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
|
||||
{
|
||||
longlong_table_creator(soci::session & sql)
|
||||
|
||||
@@ -256,126 +256,6 @@ TEST_CASE("SQLite get_last_insert_id escapes table name",
|
||||
CHECK(val == 0);
|
||||
}
|
||||
|
||||
// BLOB test
|
||||
struct blob_table_creator : public table_creator_base
|
||||
{
|
||||
blob_table_creator(soci::session & sql)
|
||||
: table_creator_base(sql)
|
||||
{
|
||||
sql <<
|
||||
"create table soci_test ("
|
||||
" id integer,"
|
||||
" img blob"
|
||||
")";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("SQLite blob", "[sqlite][blob]")
|
||||
{
|
||||
soci::session sql(backEnd, connectString);
|
||||
|
||||
blob_table_creator tableCreator(sql);
|
||||
|
||||
char buf[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
{
|
||||
// Read from default-constructed BLOB
|
||||
blob b(sql);
|
||||
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
char buf2[5];
|
||||
std::size_t read = b.read_from_start(buf2, 5);
|
||||
CHECK(read == 0);
|
||||
}
|
||||
{
|
||||
// empty, default-constructed BLOB
|
||||
blob b(sql);
|
||||
indicator ind;
|
||||
|
||||
sql << "insert into soci_test(id, img) values(1, :img)", use(b);
|
||||
sql << "select img from soci_test where id = 1", into(b, ind);
|
||||
|
||||
CHECK(ind == i_ok);
|
||||
CHECK(b.get_len() == 0);
|
||||
|
||||
sql << "delete from soci_test where id = 1";
|
||||
}
|
||||
{
|
||||
// Create new BLOB
|
||||
blob b(sql);
|
||||
|
||||
b.write_from_start(buf, sizeof(buf));
|
||||
|
||||
char substr[20];
|
||||
std::size_t i = b.read_from_start(substr, 3);
|
||||
substr[i] = '\0';
|
||||
CHECK(substr[0] == buf[0]);
|
||||
CHECK(substr[1] == buf[1]);
|
||||
CHECK(substr[2] == buf[2]);
|
||||
CHECK(substr[3] == '\0');
|
||||
|
||||
sql << "insert into soci_test(id, img) values(7, :img)", use(b);
|
||||
}
|
||||
{
|
||||
// Append to BLOB
|
||||
blob b(sql);
|
||||
|
||||
sql << "select img from soci_test where id = 7", into(b);
|
||||
CHECK(b.get_len() == sizeof(buf));
|
||||
|
||||
b.append(buf, sizeof(buf));
|
||||
|
||||
CHECK(b.get_len() == 2 * sizeof(buf));
|
||||
|
||||
sql << "update soci_test set img = :img where id = 7", use(b);
|
||||
}
|
||||
{
|
||||
// Read from BLOB as fetched from DB
|
||||
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);
|
||||
}
|
||||
{
|
||||
// Trim BLOB
|
||||
blob b(sql);
|
||||
sql << "select img from soci_test where id = 7", into(b);
|
||||
CHECK(b.get_len() == 2 * sizeof(buf));
|
||||
b.trim(0);
|
||||
CHECK(b.get_len() == 0);
|
||||
sql << "update soci_test set img = :img where id = 7", use(b);
|
||||
}
|
||||
{
|
||||
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));
|
||||
sql << "update soci_test set img=? where id = 7", use(b);
|
||||
|
||||
b.append(buf, sizeof(buf));
|
||||
CHECK(b.get_len() == 2 * sizeof(buf));
|
||||
sql << "insert into soci_test(id, img) values(8, ?)", use(b);
|
||||
}
|
||||
{
|
||||
blob b(sql);
|
||||
sql << "select img from soci_test where id = 8", 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);
|
||||
|
||||
sql << "select img from soci_test where id = 7", into(b);
|
||||
CHECK(b.get_len() == sizeof(buf));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// This test was put in to fix a problem that occurs when there are both
|
||||
// into and use elements in the same query and one of them (into) binds
|
||||
// to a vector object.
|
||||
|
||||
Reference in New Issue
Block a user