Bug #2535 » WtSessionDisconnect.patch
src/Wt/Dbo/Session | ||
---|---|---|
*/
|
||
void rereadAll(const char *tableName = 0);
|
||
/*! \brief Disconnects all objects from session management.
|
||
*
|
||
* This disconnects all objects from the session management.
|
||
* Disconnected objects are not synchronized with the database.
|
||
*/
|
||
virtual void disconnectAll();
|
||
/*! \brief Discards all unflushed changes.
|
||
*
|
||
* This method is useful when the flushMode() is set to Manual. It discards
|
||
... | ... | |
virtual void dropTable(Session& session,
|
||
std::set<std::string>& tablesDropped);
|
||
virtual void rereadAll();
|
||
virtual void disconnectAll();
|
||
std::string primaryKeys() const;
|
||
};
|
||
... | ... | |
virtual void dropTable(Session& session,
|
||
std::set<std::string>& tablesDropped);
|
||
virtual void rereadAll();
|
||
virtual void disconnectAll();
|
||
};
|
||
|
||
typedef const std::type_info * const_typeinfo_ptr;
|
src/Wt/Dbo/Session.C | ||
---|---|---|
throw Exception("Not to be done.");
|
||
}
|
||
void Session::MappingInfo::disconnectAll()
|
||
{
|
||
throw Exception("Not to be done.");
|
||
}
|
||
std::string Session::MappingInfo::primaryKeys() const
|
||
{
|
||
if (surrogateIdFieldName)
|
||
... | ... | |
i->second->rereadAll();
|
||
}
|
||
void Session::disconnectAll()
|
||
{
|
||
if (!dirtyObjects_.empty())
|
||
std::cerr << "Warning: Wt::Dbo::Session disconnecting with "
|
||
<< dirtyObjects_.size() << " dirty objects" << std::endl;
|
||
for (MetaDboBaseSet::iterator i = dirtyObjects_.begin();
|
||
i != dirtyObjects_.end(); ++i)
|
||
(*i)->decRef();
|
||
dirtyObjects_.clear();
|
||
for (ClassRegistry::iterator i = classRegistry_.begin();
|
||
i != classRegistry_.end(); ++i)
|
||
i->second->disconnectAll();
|
||
}
|
||
void Session::discardUnflushed()
|
||
{
|
||
objectsToAdd_.clear();
|
src/Wt/Dbo/Session_impl.h | ||
---|---|---|
}
|
||
template <class C>
|
||
void Session::Mapping<C>::disconnectAll()
|
||
{
|
||
for (typename Registry::iterator i = registry_.begin();
|
||
i != registry_.end(); ++i) {
|
||
i->second->setSession(0);
|
||
i->second->setState(MetaDboBase::Disconnected);
|
||
}
|
||
registry_.clear();
|
||
}
|
||
template <class C>
|
||
void Session::Mapping<C>::init(Session& session)
|
||
{
|
||
if (!initialized_) {
|
src/Wt/Dbo/ptr | ||
---|---|---|
New = 0x000,
|
||
Persisted = 0x001,
|
||
Orphaned = 0x002,
|
||
Disconnected = 0x004,
|
||
// flags
|
||
NeedsDelete = 0x010,
|
||
... | ... | |
bool isPersisted() const
|
||
{ return 0 != (state_ & (Persisted | SavedInTransaction)); }
|
||
bool isOrphaned() const { return 0 != (state_ & Orphaned); }
|
||
bool isDisconnected() const { return 0 != (state_ & Disconnected); }
|
||
bool isDeleted() const
|
||
{ return 0 != (state_ & (NeedsDelete | DeletedInTransaction)); }
|
||
... | ... | |
int refCount_;
|
||
void checkNotOrphaned();
|
||
void checkNotDisconnected();
|
||
};
|
||
/*! \class dbo_default_traits Wt/Dbo/Dbo Wt/Dbo/Dbo
|
src/Wt/Dbo/ptr.C | ||
---|---|---|
}
|
||
}
|
||
void MetaDboBase::checkNotDisconnected()
|
||
{
|
||
if (isDisconnected()) {
|
||
throw Exception("modifying disconnected dbo ptr");
|
||
}
|
||
}
|
||
ptr_base::~ptr_base()
|
||
{ }
|
||
src/Wt/Dbo/ptr_impl.h | ||
---|---|---|
if (refCount_)
|
||
throw std::logic_error("Dbo: refCount > 0");
|
||
if ((!isOrphaned()) && session())
|
||
if ((!isOrphaned()) && (!isDisconnected()) && session())
|
||
session()->prune(this);
|
||
delete obj_;
|
||
... | ... | |
void MetaDbo<C>::flush()
|
||
{
|
||
checkNotOrphaned();
|
||
checkNotDisconnected();
|
||
if (state_ & NeedsDelete) {
|
||
state_ &= ~NeedsDelete;
|
test/dbo/DboDisconnectTest.C | ||
---|---|---|
/*
|
||
* Copyright (C) 2009 Emweb bvba, Kessel-Lo, Belgium.
|
||
*
|
||
* See the LICENSE file for terms of use.
|
||
*/
|
||
#include <boost/test/unit_test.hpp>
|
||
#include <Wt/Dbo/Dbo>
|
||
#include <Wt/Dbo/backend/Postgres>
|
||
#include <Wt/Dbo/backend/MySQL>
|
||
#include <Wt/Dbo/backend/Sqlite3>
|
||
#include <Wt/Dbo/backend/Firebird>
|
||
#include <Wt/WDate>
|
||
#include <Wt/WDateTime>
|
||
#include <Wt/WTime>
|
||
#include <Wt/Dbo/WtSqlTraits>
|
||
#include <Wt/Dbo/ptr_tuple>
|
||
#include <string>
|
||
namespace dbo = Wt::Dbo;
|
||
class TestDbo;
|
||
typedef dbo::collection< dbo::ptr<TestDbo> > TestDboCollection;
|
||
class TestDbo : public Wt::Dbo::Dbo<TestDbo>
|
||
{
|
||
public:
|
||
int intC;
|
||
double doubleC;
|
||
template<class Action>
|
||
void persist(Action &a)
|
||
{
|
||
Wt::Dbo::field(a, intC, "intC");
|
||
Wt::Dbo::field(a, doubleC, "doubleC");
|
||
}
|
||
static const char *TableName()
|
||
{
|
||
return "func";
|
||
}
|
||
};
|
||
struct Dbo3Fixture
|
||
{
|
||
typedef std::map<long long, Wt::Dbo::ptr<TestDbo>> TestMapType;
|
||
TestMapType TestMap;
|
||
dbo::SqlConnection *connection_;
|
||
dbo::Session *session_;
|
||
Dbo3Fixture()
|
||
{
|
||
connection_ = new dbo::backend::Sqlite3(":memory:");
|
||
connection_->setProperty("show-queries", "true");
|
||
session_ = new dbo::Session();
|
||
session_->setConnection(*connection_);
|
||
session_->mapClass<TestDbo>(TestDbo::TableName());
|
||
session_->createTables();
|
||
{
|
||
dbo::Transaction tr(*session_);
|
||
dbo::ptr<TestDbo> New1 = session_->add(new TestDbo());
|
||
New1.modify()->intC = 1;
|
||
New1.modify()->doubleC = 1.1;
|
||
dbo::ptr<TestDbo> New2 = session_->add(new TestDbo());
|
||
New2.modify()->intC = 2;
|
||
New2.modify()->doubleC = 2.2;
|
||
}
|
||
{
|
||
//Check initial values
|
||
FetchAll();
|
||
dbo::ptr<TestDbo> DisconnectedTestPtr = TestMap[1]; //id: 1
|
||
std::cout << "Before modified: intC: " << DisconnectedTestPtr->intC << ", expected: 1" << std::endl;
|
||
//Modify from outside session_'s knowledge
|
||
dbo::Transaction tr(*session_);
|
||
session_->execute(std::string("UPDATE ") + TestDbo::TableName() + " SET intC = 99 WHERE id = 1;");
|
||
tr.commit();
|
||
//Check again
|
||
FetchAll();
|
||
//should remain unchanged because in FetchAll() none of the ptr<C>s are deleted or modified but swapped with a local TestMap object
|
||
std::cout << "After re-fetched: intC: " << DisconnectedTestPtr->intC << ", expected: 1" << std::endl;
|
||
//should be a new value because FetchAll uses a collection to map all ptr<C> with newer values from the database
|
||
dbo::ptr<TestDbo> NormalTestPtr = TestMap[1]; //id: 1
|
||
std::cout << "After re-assignment: intC: " << NormalTestPtr->intC << ", expected: 99" << std::endl;
|
||
BOOST_REQUIRE(DisconnectedTestPtr->intC == 1);
|
||
BOOST_REQUIRE(NormalTestPtr->intC == 99);
|
||
dbo::Transaction tr2(*session_);
|
||
NormalTestPtr.modify()->intC = 10;
|
||
tr2.commit();
|
||
try
|
||
{
|
||
dbo::Transaction tr3(*session_);
|
||
DisconnectedTestPtr.modify()->intC = 5;
|
||
tr3.commit();
|
||
}
|
||
catch(std::exception &e)
|
||
{
|
||
std::cout << "Exception caught: " << e.what();
|
||
}
|
||
}
|
||
}
|
||
void FetchAll()
|
||
{
|
||
//Strong exception safety(make TestMap empty by swapping with an empty map, swap back if exception is caught)
|
||
TestMapType testmap;
|
||
TestMap.swap(testmap);
|
||
session_->disconnectAll();
|
||
try
|
||
{
|
||
dbo::Transaction tr(*session_);
|
||
TestDboCollection collection = session_->find<TestDbo>();
|
||
for(TestDboCollection::const_iterator itr = collection.begin();
|
||
itr != collection.end();
|
||
++itr)
|
||
{
|
||
TestMap[itr->id()] = *itr;
|
||
}
|
||
tr.commit();
|
||
}
|
||
catch(...)
|
||
{
|
||
testmap.swap(TestMap);
|
||
}
|
||
}
|
||
~Dbo3Fixture()
|
||
{
|
||
session_->dropTables();
|
||
delete session_;
|
||
delete connection_;
|
||
}
|
||
};
|
||
BOOST_AUTO_TEST_CASE( dbo3_reload_test )
|
||
{
|
||
Dbo3Fixture f;
|
||
}
|
- « Previous
- 1
- 2
- Next »