mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 04:03:04 +01:00
Fixed #7579: Cannot nbackup a firebird 3.0 database in firebird 4.0 service with engine12 setup in Providers
(cherry picked from commit d868e7ea78
)
This commit is contained in:
parent
2d640d63ba
commit
467f43a927
@ -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");
|
||||
|
@ -66,6 +66,7 @@ public:
|
||||
|
||||
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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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&,
|
||||
@ -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)
|
||||
@ -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)
|
||||
@ -6296,7 +6296,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;
|
||||
@ -7860,7 +7860,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)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -7874,7 +7874,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));
|
||||
}
|
||||
|
@ -623,8 +623,6 @@ 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);
|
||||
@ -632,6 +630,9 @@ int gstat(Firebird::UtilSvc* uSvc)
|
||||
// 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
|
||||
|
@ -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
|
||||
{
|
||||
@ -52,6 +48,7 @@ class YService;
|
||||
class YStatement;
|
||||
class IscStatement;
|
||||
class YTransaction;
|
||||
class Dispatcher;
|
||||
|
||||
class YObject
|
||||
{
|
||||
@ -597,7 +594,7 @@ class YService FB_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();
|
||||
@ -622,6 +619,11 @@ public:
|
||||
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 FB_FINAL :
|
||||
@ -646,6 +648,12 @@ public:
|
||||
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);
|
||||
|
@ -6124,12 +6124,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);
|
||||
}
|
||||
|
||||
@ -6187,8 +6188,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)
|
||||
{
|
||||
@ -6221,6 +6222,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)
|
||||
{
|
||||
@ -6416,66 +6454,16 @@ 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))
|
||||
{
|
||||
string spb_config;
|
||||
spbWriter.getString(spb_config);
|
||||
Config::merge(config, &spb_config);
|
||||
}
|
||||
|
||||
StatusVector temp(NULL);
|
||||
CheckStatusWrapper tempCheckStatusWrapper(&temp);
|
||||
CheckStatusWrapper* currentStatus = status;
|
||||
|
||||
for (GetPlugins<IProvider> providerIterator(IPluginManager::TYPE_PROVIDER, config);
|
||||
providerIterator.hasData();
|
||||
providerIterator.next())
|
||||
{
|
||||
IProvider* p = providerIterator.plugin();
|
||||
|
||||
if (cryptCallback)
|
||||
{
|
||||
p->setDbCryptCallback(currentStatus, cryptCallback);
|
||||
if (currentStatus->getState() & IStatus::STATE_ERRORS)
|
||||
continue;
|
||||
}
|
||||
|
||||
service = p->attachServiceManager(currentStatus, svcName.c_str(),
|
||||
spbWriter.getBufferLength(), spbWriter.getBuffer());
|
||||
|
||||
if (!(currentStatus->getState() & IStatus::STATE_ERRORS))
|
||||
{
|
||||
if (status != currentStatus)
|
||||
{
|
||||
status->setErrors(currentStatus->getErrors());
|
||||
status->setWarnings(currentStatus->getWarnings());
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
currentStatus->init();
|
||||
}
|
||||
IProvider* p;
|
||||
service = internalServiceAttach(status, svcName, spbWriter,
|
||||
[](CheckStatusWrapper*, IService*){ }, &p);
|
||||
|
||||
if (!(status->getState() & IStatus::STATE_ERRORS))
|
||||
{
|
||||
(Arg::Gds(isc_service_att_err) <<
|
||||
Arg::Gds(isc_no_providers)).copyTo(status);
|
||||
YService* r = FB_NEW YService(p, service, utfData, this);
|
||||
r->addRef();
|
||||
r->attachSpb.reset(spbWriter);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
catch (const Exception& e)
|
||||
@ -6493,6 +6481,87 @@ YService* Dispatcher::attachServiceManager(CheckStatusWrapper* status, const cha
|
||||
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)
|
||||
{
|
||||
p->setDbCryptCallback(currentStatus, cryptCallback);
|
||||
if (currentStatus->getState() & IStatus::STATE_ERRORS)
|
||||
continue;
|
||||
}
|
||||
|
||||
service = p->attachServiceManager(currentStatus, svcName.c_str(),
|
||||
spb.getBufferLength(), spb.getBuffer());
|
||||
|
||||
if (!(currentStatus->getState() & IStatus::STATE_ERRORS))
|
||||
{
|
||||
start(currentStatus, service);
|
||||
|
||||
if (!(currentStatus->getState() & IStatus::STATE_ERRORS))
|
||||
{
|
||||
fb_utils::copyStatus(status, currentStatus);
|
||||
if (retProvider)
|
||||
{
|
||||
p->addRef();
|
||||
*retProvider = p;
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
}
|
||||
|
||||
switch (currentStatus->getErrors()[1])
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static std::atomic<SLONG> shutdownWaiters(0);
|
||||
static const SLONG SHUTDOWN_COMPLETE = 1;
|
||||
static const SLONG SHUTDOWN_STEP = 2;
|
||||
|
Loading…
Reference in New Issue
Block a user