Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix row::move_as behavior breaking reusability #1145

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/private/soci-trivial-blob-backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define SOCI_PRIVATE_SOCI_TRIVIAL_BLOB_BACKEND_H_INCLUDED

#include "soci/soci-backend.h"
#include "soci/session.h"

#include <vector>
#include <cstring>
Expand All @@ -22,6 +23,8 @@ namespace details
class trivial_blob_backend : public details::blob_backend
{
public:
trivial_blob_backend(details::session_backend &backend) : session_(backend) {}

std::size_t get_len() override { return buffer_.size(); }

std::size_t read_from_start(void* buf, std::size_t toRead,
Expand Down Expand Up @@ -71,7 +74,10 @@ class trivial_blob_backend : public details::blob_backend

const std::uint8_t *get_buffer() const { return buffer_.data(); }

details::session_backend &get_session_backend() override { return session_; }

protected:
details::session_backend &session_;
std::vector< std::uint8_t > buffer_;
};

Expand Down
1 change: 1 addition & 0 deletions include/soci/blob.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class SOCI_DECL blob

// (Re)initializes this blob
void initialize(session &s);
void initialize(details::blob_backend *backend);

std::size_t get_len();

Expand Down
1 change: 1 addition & 0 deletions include/soci/db2/soci-db2.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ struct db2_blob_backend : details::blob_backend
std::size_t write_from_start(const void* buf, std::size_t toWrite, std::size_t offset = 0) override;
std::size_t append(const void* buf, std::size_t toWrite) override;
void trim(std::size_t newLen) override;
details::session_backend &get_session_backend() override;

db2_session_backend& session_;
};
Expand Down
2 changes: 2 additions & 0 deletions include/soci/empty/soci-empty.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ struct empty_blob_backend : details::blob_backend
std::size_t append(const void* buf, std::size_t toWrite) override;
void trim(std::size_t newLen) override;

details::session_backend &get_session_backend() override;

empty_session_backend& session_;
};

Expand Down
2 changes: 2 additions & 0 deletions include/soci/firebird/soci-firebird.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ struct firebird_blob_backend : details::blob_backend
std::size_t append(const void *buf, std::size_t toWrite) override;
void trim(std::size_t newLen) override;

details::session_backend &get_session_backend() override;

// Writes the current data into the database by allocating a new BLOB
// object for it.
//
Expand Down
1 change: 1 addition & 0 deletions include/soci/odbc/soci-odbc.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ struct odbc_blob_backend : details::blob_backend
std::size_t write_from_start(const void *buf, std::size_t toWrite, std::size_t offset = 0) override;
std::size_t append(const void *buf, std::size_t toWrite) override;
void trim(std::size_t newLen) override;
details::session_backend &get_session_backend() override;

odbc_session_backend &session_;
};
Expand Down
4 changes: 3 additions & 1 deletion include/soci/oracle/soci-oracle.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,14 @@ struct oracle_blob_backend : details::blob_backend

locator_t get_lob_locator() const;

void set_lob_locator(locator_t locator, bool initialized = true);
void set_lob_locator(const locator_t locator, bool initialized = true);

void reset();

void ensure_initialized();

details::session_backend &get_session_backend() override;

private:
std::size_t do_deprecated_read(std::size_t offset, void *buf, std::size_t toRead) override
{
Expand Down
2 changes: 2 additions & 0 deletions include/soci/postgresql/soci-postgresql.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ class postgresql_blob_backend : public details::blob_backend

void reset();

details::session_backend &get_session_backend() override;

private:
postgresql_session_backend & session_;
blob_details details_;
Expand Down
5 changes: 5 additions & 0 deletions include/soci/row.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ class SOCI_DECL row

T ret;
type_conversion<T>::move_from_base(baseVal, *indicators_.at(pos), ret);

// Re-initialize the holder in order to be able to use this row object
// for binding to another data set
baseVal = T{};

return ret;
}

Expand Down
4 changes: 4 additions & 0 deletions include/soci/soci-backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ class rowid_backend
virtual ~rowid_backend() {}
};

class session_backend;

// polymorphic blob backend

class blob_backend
Expand All @@ -312,6 +314,8 @@ class blob_backend

virtual void trim(std::size_t newLen) = 0;

virtual session_backend &get_session_backend() = 0;

// Deprecated functions with backend-specific semantics preserved only for
// compatibility.
[[deprecated("Use read_from_start instead")]]
Expand Down
5 changes: 5 additions & 0 deletions src/backends/db2/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ void db2_blob_backend::trim(std::size_t /* newLen */)
throw soci_error("BLOBs are not supported.");
}

details::session_backend &db2_blob_backend::get_session_backend()
{
return session_;
}

#ifdef _MSC_VER
# pragma warning(pop)
#endif
5 changes: 5 additions & 0 deletions src/backends/empty/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ void empty_blob_backend::trim(std::size_t /* newLen */)
throw soci_error("BLOBs are not supported.");
}

details::session_backend &empty_blob_backend::get_session_backend()
{
return session_;
}

#ifdef _MSC_VER
# pragma warning(pop)
#endif
5 changes: 5 additions & 0 deletions src/backends/firebird/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,8 @@ long firebird_blob_backend::getBLOBInfo()

return total_length;
}

details::session_backend &firebird_blob_backend::get_session_backend()
{
return session_;
}
4 changes: 2 additions & 2 deletions src/backends/mysql/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
using namespace soci;
using namespace soci::details;

mysql_blob_backend::mysql_blob_backend(mysql_session_backend &)
: details::trivial_blob_backend()
mysql_blob_backend::mysql_blob_backend(mysql_session_backend &backend)
: details::trivial_blob_backend(backend)
{
}

Expand Down
5 changes: 5 additions & 0 deletions src/backends/odbc/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ void odbc_blob_backend::trim(std::size_t /* newLen */)
throw soci_error("BLOBs are not supported.");
}

details::session_backend &odbc_blob_backend::get_session_backend()
{
return session_;
}

#ifdef _MSC_VER
# pragma warning(pop)
#endif
13 changes: 11 additions & 2 deletions src/backends/oracle/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ oracle_blob_backend::locator_t oracle_blob_backend::get_lob_locator() const
return lobp_;
}

void oracle_blob_backend::set_lob_locator(oracle_blob_backend::locator_t locator, bool initialized)
void oracle_blob_backend::set_lob_locator(const oracle_blob_backend::locator_t locator, bool initialized)
{
// If we select a BLOB value into a BLOB object, then the post_fetch code in
// the standard_into_type_backend will set this object's locator to the one it is
Expand All @@ -157,7 +157,11 @@ void oracle_blob_backend::set_lob_locator(oracle_blob_backend::locator_t locator
{
reset();

lobp_ = locator;
sword res = OCILobLocatorAssign(session_.svchp_, session_.errhp_, locator, &lobp_);
if (res != OCI_SUCCESS)
{
throw_oracle_soci_error(res, session_.errhp_);
}
}

initialized_ = initialized;
Expand Down Expand Up @@ -239,3 +243,8 @@ void oracle_blob_backend::ensure_initialized()
initialized_ = true;
}
}

details::session_backend &oracle_blob_backend::get_session_backend()
{
return session_;
}
24 changes: 20 additions & 4 deletions src/backends/oracle/standard-into-type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <ctime>
#include <sstream>

#include <oci.h>

#ifdef _MSC_VER
#pragma warning(disable:4355)
#endif
Expand Down Expand Up @@ -157,11 +159,24 @@ void oracle_standard_into_type_backend::define_by_pos(
oracle_blob_backend *bbe
= static_cast<oracle_blob_backend *>(b->get_backend());

// Reset the blob to ensure that a potentially open temporary BLOB gets
// freed before the locator is changed to point to a different BLOB by the
// to-be-executed statement (which would leave us with a dangling temporary BLOB)
// Reset the blob to ensure that even when the query fails,
// the blob does not contain leftover data from whatever it
// contained before.
bbe->reset();
ociData_ = bbe->get_lob_locator();

// Allocate our very own LOB locator. We have to do this instead of
// reusing the locator from the existing Blob object in case the
// statement for which we are binding is going to be executed multiple
// times. If we borrowed the locator from the Blob object, consecutive
// queries would override a previous locator (which might belong
// to an independent Blob object by now).
sword res = OCIDescriptorAlloc(statement_.session_.envhp_,
reinterpret_cast<dvoid**>(&ociData_), OCI_DTYPE_LOB, 0, 0);
if (res != OCI_SUCCESS)
{
throw soci_error("Cannot allocate the LOB locator");
}


size = sizeof(ociData_);
data = &ociData_;
Expand Down Expand Up @@ -384,6 +399,7 @@ void oracle_standard_into_type_backend::clean_up()

if (type_ == x_blob)
{
OCIDescriptorFree(ociData_, OCI_DTYPE_LOB);
ociData_ = NULL;
}

Expand Down
5 changes: 5 additions & 0 deletions src/backends/postgresql/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,8 @@ void postgresql_blob_backend::clone()
lo_close(session_.conn_, old_details.fd);
}
}

details::session_backend &postgresql_blob_backend::get_session_backend()
{
return session_;
}
4 changes: 2 additions & 2 deletions src/backends/sqlite3/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

using namespace soci;

sqlite3_blob_backend::sqlite3_blob_backend(sqlite3_session_backend &)
: details::trivial_blob_backend()
sqlite3_blob_backend::sqlite3_blob_backend(sqlite3_session_backend &backend)
: details::trivial_blob_backend(backend)
{
}

Expand Down
7 changes: 6 additions & 1 deletion src/core/blob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ bool blob::is_valid() const

void blob::initialize(session &session)
{
backEnd_.reset(session.make_blob_backend());
initialize(session.make_blob_backend());
}

void blob::initialize(details::blob_backend *backend)
{
backEnd_.reset(backend);
}

std::size_t blob::get_len()
Expand Down
4 changes: 4 additions & 0 deletions src/core/row.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,9 @@ blob row::move_as<blob>(std::size_t pos) const

blob ret;
type_conversion<blob>::move_from_base(baseVal, *indicators_.at(pos), ret);

// Re-initialize blob object so it can be used in further queries
baseVal.initialize(ret.get_backend()->get_session_backend().make_blob_backend());

return ret;
}
20 changes: 12 additions & 8 deletions tests/common-tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -6853,17 +6853,21 @@ TEST_CASE_METHOD(common_tests, "BLOB", "[core][blob]")
SECTION("Blob binding")
{
// Add data
soci::blob blob(sql);
soci::blob blob1(sql);
soci::blob blob2(sql);
static_assert(10 <= sizeof(dummy_data), "Underlying assumption violated");
blob.write_from_start(dummy_data, 10);
const int id = 42;
sql << "insert into soci_test (id, b) values(:id, :b)", soci::use(id), soci::use(blob);
blob1.write_from_start(dummy_data, 10);
blob2.write_from_start(dummy_data, 10);
const int id1 = 42;
const int id2 = 42;
sql << "insert into soci_test (id, b) values(:id, :b)", soci::use(id1), soci::use(blob1);
sql << "insert into soci_test (id, b) values(:id, :b)", soci::use(id2), soci::use(blob2);

SECTION("into")
{
soci::blob intoBlob(sql);

sql << "select b from soci_test where id=:id", soci::use(id), soci::into(intoBlob);
sql << "select b from soci_test where id=:id", soci::use(id1), soci::into(intoBlob);

char buffer[20];
std::size_t written = intoBlob.read_from_start(buffer, sizeof(buffer));
Expand All @@ -6875,7 +6879,7 @@ TEST_CASE_METHOD(common_tests, "BLOB", "[core][blob]")
}
SECTION("move_as")
{
soci::rowset< soci::row > rowSet = (sql.prepare << "select b from soci_test where id=:id", soci::use(id));
soci::rowset< soci::row > rowSet = (sql.prepare << "select b from soci_test where id=:id", soci::use(id1));
bool containedData = false;
for (auto it = rowSet.begin(); it != rowSet.end(); ++it)
{
Expand All @@ -6897,8 +6901,8 @@ TEST_CASE_METHOD(common_tests, "BLOB", "[core][blob]")
}
SECTION("reusing bound blob")
{
int secondID = id + 1;
sql << "insert into soci_test(id, b) values(:id, :b)", soci::use(secondID), soci::use(blob);
int secondID = id2 + 1;
sql << "insert into soci_test(id, b) values(:id, :b)", soci::use(secondID), soci::use(blob2);

// Selecting the blob associated with secondID should yield the same result as selecting the one for id
soci::blob intoBlob(sql);
Expand Down