Skip to content

Commit

Permalink
Fixed #7579: Cannot nbackup a firebird 3.0 database in firebird 4.0 s…
Browse files Browse the repository at this point in the history
…ervice with engine12 setup in Providers
  • Loading branch information
AlexPeshkoff authored Jun 13, 2023
1 parent cb52a49 commit d868e7e
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 71 deletions.
5 changes: 5 additions & 0 deletions src/common/classes/ClumpletWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ void ClumpletWriter::reset(const UCHAR* buffer, const FB_SIZE_T buffLen)
rewind();
}

void ClumpletWriter::reset(const ClumpletWriter& from)
{
reset(from.getBuffer(), from.getBufferEnd() - from.getBuffer());
}

void ClumpletWriter::size_overflow()
{
fatal_exception::raise("Clumplet buffer size limit reached");
Expand Down
1 change: 1 addition & 0 deletions src/common/classes/ClumpletWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class ClumpletWriter : public ClumpletReader

void reset(UCHAR tag = 0);
void reset(const UCHAR* buffer, const FB_SIZE_T buffLen);
void reset(const ClumpletWriter& from);
void clear();

// Methods to create new clumplet at current position
Expand Down
5 changes: 5 additions & 0 deletions src/include/firebird/Interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@ namespace Firebird
return !hasData();
}

bool isSuccess() const
{
return isEmpty();
}

static void setVersionError(IStatus* status, const char* interfaceName,
unsigned currentVersion, unsigned expectedVersion)
{
Expand Down
12 changes: 6 additions & 6 deletions src/remote/client/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,7 @@ static void enqueue_receive(rem_port*, t_rmtque_fn, Rdb*, void*, Rrq::rrq_repeat
static void dequeue_receive(rem_port*);
static THREAD_ENTRY_DECLARE event_thread(THREAD_ENTRY_PARAM);
static Rvnt* find_event(rem_port*, SLONG);
static bool get_new_dpb(ClumpletWriter&, const ParametersSet&);
static bool get_new_dpb(ClumpletWriter&, const ParametersSet&, bool);
static void info(CheckStatusWrapper*, Rdb*, P_OP, USHORT, USHORT, USHORT,
const UCHAR*, USHORT, const UCHAR*, ULONG, UCHAR*);
static bool init(CheckStatusWrapper*, ClntAuthBlock&, rem_port*, P_OP, PathName&,
Expand Down Expand Up @@ -1186,7 +1186,7 @@ IAttachment* RProvider::attach(CheckStatusWrapper* status, const char* filename,
ClumpletWriter newDpb(ClumpletReader::dpbList, MAX_DPB_SIZE, dpb, dpb_length);
unsigned flags = ANALYZE_MOUNTS;

if (get_new_dpb(newDpb, dpbParam))
if (get_new_dpb(newDpb, dpbParam, loopback))
flags |= ANALYZE_USER_VFY;

if (loopback)
Expand Down Expand Up @@ -1866,7 +1866,7 @@ Firebird::IAttachment* RProvider::create(CheckStatusWrapper* status, const char*
reinterpret_cast<const UCHAR*>(dpb), dpb_length);
unsigned flags = ANALYZE_MOUNTS;

if (get_new_dpb(newDpb, dpbParam))
if (get_new_dpb(newDpb, dpbParam, loopback))
flags |= ANALYZE_USER_VFY;

if (loopback)
Expand Down Expand Up @@ -6532,7 +6532,7 @@ Firebird::IService* RProvider::attachSvc(CheckStatusWrapper* status, const char*
PathName node_name, expanded_name(service);

ClumpletWriter newSpb(ClumpletReader::spbList, MAX_DPB_SIZE, spb, spbLength);
const bool user_verification = get_new_dpb(newSpb, spbParam);
const bool user_verification = get_new_dpb(newSpb, spbParam, loopback);

ClntAuthBlock cBlock(NULL, &newSpb, &spbParam);
unsigned flags = 0;
Expand Down Expand Up @@ -8073,7 +8073,7 @@ static Rvnt* find_event( rem_port* port, SLONG id)
}


static bool get_new_dpb(ClumpletWriter& dpb, const ParametersSet& par)
static bool get_new_dpb(ClumpletWriter& dpb, const ParametersSet& par, bool loopback)
{
/**************************************
*
Expand All @@ -8087,7 +8087,7 @@ static bool get_new_dpb(ClumpletWriter& dpb, const ParametersSet& par)
*
**************************************/
bool redirection = Config::getRedirection();
if (((!redirection) && dpb.find(par.address_path)) || dpb.find(par.map_attach))
if (((loopback || !redirection) && dpb.find(par.address_path)) || dpb.find(par.map_attach))
{
status_exception::raise(Arg::Gds(isc_unavailable));
}
Expand Down
5 changes: 3 additions & 2 deletions src/utilities/gstat/dba.epp
Original file line number Diff line number Diff line change
Expand Up @@ -618,15 +618,16 @@ int gstat(Firebird::UtilSvc* uSvc)
tddba->page_number = -1;
const header_page* header = (const header_page*) db_read((SLONG) 0);

uSvc->started();

if (!Ods::isSupported(header))
{
const int oversion = (header->hdr_ods_version & ~ODS_FIREBIRD_FLAG);
dba_error(3, SafeArg() << ODS_VERSION << oversion);
// msg 3: Wrong ODS version, expected %d, encountered %d?
}

// it's important for provider auto-select to mark as 'started' after possible network error
uSvc->started();

char file_name[1024];
fileName.copyTo(file_name, sizeof(file_name));
dba_print(false, 6, SafeArg() << file_name); // msg 6: \nDatabase \"@1\"\n
Expand Down
20 changes: 14 additions & 6 deletions src/yvalve/YObjects.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,7 @@
#include "../common/classes/alloc.h"
#include "../common/classes/array.h"
#include "../common/MsgMetadata.h"

namespace Firebird
{
class ClumpletWriter;
}
#include "../common/classes/ClumpletWriter.h"

namespace Why
{
Expand All @@ -52,6 +48,7 @@ class YService;
class YStatement;
class IscStatement;
class YTransaction;
class Dispatcher;

class YObject
{
Expand Down Expand Up @@ -600,7 +597,7 @@ class YService final :
public:
static const ISC_STATUS ERROR_CODE = isc_bad_svc_handle;

YService(Firebird::IProvider* aProvider, Firebird::IService* aNext, bool utf8);
YService(Firebird::IProvider* aProvider, Firebird::IService* aNext, bool utf8, Dispatcher* yProvider);
~YService();

void shutdown();
Expand All @@ -625,6 +622,11 @@ class YService final :
private:
Firebird::IProvider* provider;
bool utf8Connection; // Client talks to us using UTF8, else - system default charset

public:
Firebird::RefPtr<IService> alternativeHandle;
Firebird::ClumpletWriter attachSpb;
Firebird::RefPtr<Dispatcher> ownProvider;
};

class Dispatcher final :
Expand All @@ -649,6 +651,12 @@ class Dispatcher final :
void destroy(unsigned)
{ }

public:
Firebird::IService* internalServiceAttach(Firebird::CheckStatusWrapper* status,
const Firebird::PathName& svcName, Firebird::ClumpletReader& spb,
std::function<void(Firebird::CheckStatusWrapper*, Firebird::IService*)> start,
Firebird::IProvider** retProvider);

private:
YAttachment* attachOrCreateDatabase(Firebird::CheckStatusWrapper* status, bool createFlag,
const char* filename, unsigned int dpbLength, const unsigned char* dpb);
Expand Down
184 changes: 127 additions & 57 deletions src/yvalve/why.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6223,12 +6223,13 @@ YReplicator* YAttachment::createReplicator(CheckStatusWrapper* status)
//-------------------------------------


YService::YService(IProvider* aProvider, IService* aNext, bool utf8)
YService::YService(IProvider* aProvider, IService* aNext, bool utf8, Dispatcher* yProvider)
: YHelper(aNext),
provider(aProvider),
utf8Connection(utf8)
utf8Connection(utf8),
attachSpb(getPool(), ClumpletReader::spbList, MAX_DPB_SIZE, nullptr, 0),
ownProvider(yProvider)
{
provider->addRef();
makeHandle(&services, this, handle);
}

Expand Down Expand Up @@ -6286,8 +6287,8 @@ void YService::query(CheckStatusWrapper* status, unsigned int sendLength, const
try
{
YEntry<YService> entry(status, this);
entry.next()->query(status, sendLength, sendItems,
receiveLength, receiveItems, bufferLength, buffer);
(alternativeHandle ? alternativeHandle.getPtr() : entry.next())->
query(status, sendLength, sendItems, receiveLength, receiveItems, bufferLength, buffer);
}
catch (const Exception& e)
{
Expand Down Expand Up @@ -6320,6 +6321,43 @@ void YService::start(CheckStatusWrapper* status, unsigned int spbLength, const u

YEntry<YService> entry(status, this);
entry.next()->start(status, spb.getBufferLength(), spb.getBuffer());

const ISC_STATUS retryList[] = {isc_wrong_ods, isc_badodsver, isc_gstat_wrong_ods, 0};

for (const ISC_STATUS* code = retryList; *code; ++code)
{
if (fb_utils::containsErrorCode(status->getErrors(), *code))
{
FbLocalStatus st;
if (alternativeHandle) // first of all try already found provider
{
alternativeHandle->start(&st, spb.getBufferLength(), spb.getBuffer());
if (st.isSuccess())
{
status->init();
return;
}
st->clearException();
}

// we are not going to attach network providers, therefore const svcName is OK
alternativeHandle = ownProvider->internalServiceAttach(&st, "service_mgr", attachSpb,
[&spb](CheckStatusWrapper* st, IService* service)
{
service->start(st, spb.getBufferLength(), spb.getBuffer());
}, nullptr);
if (st.isSuccess())
{
status->init();
return;
}

// can't help any more...
break;
}
}

alternativeHandle = nullptr;
}
catch (const Exception& e)
{
Expand Down Expand Up @@ -6515,78 +6553,110 @@ YService* Dispatcher::attachServiceManager(CheckStatusWrapper* status, const cha
IntlSpb().toUtf8(spbWriter);
}

// Build correct config
RefPtr<const Config> config(Config::getDefaultConfig());
if (spbWriter.find(isc_spb_config))
IProvider* p;
service = internalServiceAttach(status, svcName, spbWriter,
[](CheckStatusWrapper*, IService*){ }, &p);

if (!(status->getState() & IStatus::STATE_ERRORS))
{
string spb_config;
spbWriter.getString(spb_config);
Config::merge(config, &spb_config);
YService* r = FB_NEW YService(p, service, utfData, this);
r->addRef();
r->attachSpb.reset(spbWriter);
return r;
}
}
catch (const Exception& e)
{
if (service)
{
StatusVector temp(NULL);
CheckStatusWrapper tempCheckStatusWrapper(&temp);
service->detach(&tempCheckStatusWrapper);
}

StatusVector temp(NULL);
CheckStatusWrapper tempCheckStatusWrapper(&temp);
CheckStatusWrapper* currentStatus = status;
e.stuffException(status);
}

for (GetPlugins<IProvider> providerIterator(IPluginManager::TYPE_PROVIDER, config);
providerIterator.hasData();
providerIterator.next())
return NULL;
}


// Attach and probably start a service through the first available subsystem.
IService* Dispatcher::internalServiceAttach(CheckStatusWrapper* status, const PathName& svcName,
ClumpletReader& spb, std::function<void(CheckStatusWrapper*, IService*)> start,
IProvider** retProvider)
{
IService* service = NULL;

// Build correct config
RefPtr<const Config> config(Config::getDefaultConfig());
if (spb.find(isc_spb_config))
{
string spb_config;
spb.getString(spb_config);
Config::merge(config, &spb_config);
}

FbLocalStatus temp1, temp2;
CheckStatusWrapper* currentStatus = &temp1;

for (GetPlugins<IProvider> providerIterator(IPluginManager::TYPE_PROVIDER, config);
providerIterator.hasData();
providerIterator.next())
{
IProvider* p = providerIterator.plugin();

if (cryptCallback)
{
IProvider* p = providerIterator.plugin();
p->setDbCryptCallback(currentStatus, cryptCallback);
if (currentStatus->getState() & IStatus::STATE_ERRORS)
continue;
}

if (cryptCallback)
{
p->setDbCryptCallback(currentStatus, cryptCallback);
if (currentStatus->getState() & IStatus::STATE_ERRORS)
continue;
}
service = p->attachServiceManager(currentStatus, svcName.c_str(),
spb.getBufferLength(), spb.getBuffer());

service = p->attachServiceManager(currentStatus, svcName.c_str(),
spbWriter.getBufferLength(), spbWriter.getBuffer());
if (!(currentStatus->getState() & IStatus::STATE_ERRORS))
{
start(currentStatus, service);

if (!(currentStatus->getState() & IStatus::STATE_ERRORS))
{
if (status != currentStatus)
fb_utils::copyStatus(status, currentStatus);
if (retProvider)
{
status->setErrors(currentStatus->getErrors());
status->setWarnings(currentStatus->getWarnings());
p->addRef();
*retProvider = p;
}
YService* r = FB_NEW YService(p, service, utfData);
r->addRef();
return r;
}

switch (currentStatus->getErrors()[1])
{
case isc_service_att_err:
currentStatus = &tempCheckStatusWrapper;
// fall down...
case isc_unavailable:
break;

default:
return NULL;
return service;
}

currentStatus->init();
}

if (!(status->getState() & IStatus::STATE_ERRORS))
switch (currentStatus->getErrors()[1])
{
(Arg::Gds(isc_service_att_err) <<
Arg::Gds(isc_no_providers)).copyTo(status);
case isc_service_att_err:
currentStatus = &temp2;
// fall down...
case isc_unavailable:
case isc_wrong_ods:
case isc_badodsver:
case isc_gstat_wrong_ods:
break;

default:
fb_utils::copyStatus(status, &temp1);
return NULL;
}

currentStatus->init();
}
catch (const Exception& e)
{
if (service)
{
StatusVector temp(NULL);
CheckStatusWrapper tempCheckStatusWrapper(&temp);
service->detach(&tempCheckStatusWrapper);
}

e.stuffException(status);
fb_utils::copyStatus(status, &temp1);
if (!(status->getState() & IStatus::STATE_ERRORS))
{
(Arg::Gds(isc_service_att_err) <<
Arg::Gds(isc_no_providers)).copyTo(status);
}

return NULL;
Expand Down

0 comments on commit d868e7e

Please sign in to comment.