8
0
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:
Alexander Peshkov 2023-06-13 18:16:37 +03:00 committed by AlexPeshkoff
parent 2d640d63ba
commit 467f43a927
7 changed files with 165 additions and 76 deletions

View File

@ -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");

View File

@ -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

View File

@ -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)
{

View File

@ -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));
}

View File

@ -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

View File

@ -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);

View File

@ -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;