mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 18:03:04 +01:00
Fixed CORE-2634: Performance regression when restoring database with big metadata
This commit is contained in:
parent
29819be1fa
commit
57b400137d
305
src/common/classes/Hash.h
Normal file
305
src/common/classes/Hash.h
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* PROGRAM: JRD Access Method
|
||||
* MODULE: Hash.h
|
||||
* DESCRIPTION: Hash of objects
|
||||
*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Alexander Peshkoff
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2009 Alexander Peshkoff <peshkoff@mail.ru>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CLASSES_HASH_H
|
||||
#define CLASSES_HASH_H
|
||||
|
||||
#include "../common/classes/vector.h"
|
||||
|
||||
namespace Firebird {
|
||||
template <typename K>
|
||||
class DefaultHash
|
||||
{
|
||||
public:
|
||||
static size_t hash(const void* value, size_t length, size_t hashSize)
|
||||
{
|
||||
size_t sum = 0;
|
||||
|
||||
const size_t* l = static_cast<const size_t*>(value);
|
||||
while (length >= sizeof(size_t))
|
||||
{
|
||||
sum += *l++;
|
||||
length -= sizeof(size_t);
|
||||
}
|
||||
|
||||
if (length)
|
||||
{
|
||||
size_t last = 0;
|
||||
memcpy(&last, l, length);
|
||||
sum += last;
|
||||
}
|
||||
|
||||
size_t rc = 0;
|
||||
while (sum)
|
||||
{
|
||||
rc += (sum % hashSize);
|
||||
sum /= hashSize;
|
||||
}
|
||||
|
||||
return rc % hashSize;
|
||||
}
|
||||
|
||||
static size_t hash(const K& value, size_t hashSize)
|
||||
{
|
||||
return hash(&value, sizeof value, hashSize);
|
||||
}
|
||||
|
||||
const static size_t DEFAULT_SIZE = 97; // largest prime number < 100
|
||||
};
|
||||
|
||||
template <typename C,
|
||||
size_t HASHSIZE = DefaultHash<C>::DEFAULT_SIZE,
|
||||
typename K = C, // default key
|
||||
typename KeyOfValue = DefaultKeyValue<C>, // default keygen
|
||||
typename F = DefaultHash<K> > // hash function definition
|
||||
class Hash
|
||||
{
|
||||
public:
|
||||
class iterator;
|
||||
friend class iterator;
|
||||
class Entry;
|
||||
friend class Entry;
|
||||
|
||||
class Entry
|
||||
{
|
||||
// This class is supposed to be used as a BASE class for class to be hashed
|
||||
private:
|
||||
Entry** previousElement;
|
||||
Entry* nextElement;
|
||||
|
||||
public:
|
||||
Entry() : previousElement(NULL) { }
|
||||
|
||||
virtual ~Entry() {
|
||||
unLink();
|
||||
}
|
||||
|
||||
void link(Entry** where)
|
||||
{
|
||||
unLink();
|
||||
|
||||
// set our pointers
|
||||
previousElement = where;
|
||||
nextElement = previousElement ? *previousElement : NULL;
|
||||
|
||||
// make next element (if present) to point to us
|
||||
if (nextElement)
|
||||
{
|
||||
nextElement->previousElement = &nextElement;
|
||||
}
|
||||
|
||||
// make previous element point to us
|
||||
*previousElement = this;
|
||||
}
|
||||
|
||||
void unLink()
|
||||
{
|
||||
// if we are linked
|
||||
if (previousElement)
|
||||
{
|
||||
if (nextElement)
|
||||
{
|
||||
// adjust previous pointer in next element ...
|
||||
nextElement->previousElement = previousElement;
|
||||
}
|
||||
// ... and next pointer in previous element
|
||||
*previousElement = nextElement;
|
||||
// finally mrk ourself not linked
|
||||
previousElement = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Entry** nextPtr()
|
||||
{
|
||||
return &nextElement;
|
||||
}
|
||||
|
||||
Entry* next() const
|
||||
{
|
||||
return nextElement;
|
||||
}
|
||||
|
||||
virtual bool isEqual(const K&) = 0;
|
||||
virtual C* get() = 0;
|
||||
}; // class Entry
|
||||
|
||||
private:
|
||||
Hash(const Hash&); // not implemented
|
||||
|
||||
public:
|
||||
explicit Hash(MemoryPool&)
|
||||
{
|
||||
memset(data, 0, sizeof data);
|
||||
}
|
||||
|
||||
Hash()
|
||||
{
|
||||
memset(data, 0, sizeof data);
|
||||
}
|
||||
|
||||
~Hash()
|
||||
{
|
||||
for (size_t n = 0; n < HASHSIZE; ++n)
|
||||
{
|
||||
while (data[n])
|
||||
{
|
||||
data[n]->unLink();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Entry* data[HASHSIZE];
|
||||
|
||||
Entry** locate(const K& key, size_t h)
|
||||
{
|
||||
Entry** pointer = &data[h];
|
||||
while (*pointer)
|
||||
{
|
||||
if ((*pointer)->isEqual(key))
|
||||
{
|
||||
break;
|
||||
}
|
||||
pointer = (*pointer)->nextPtr();
|
||||
}
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
Entry** locate(const K& key)
|
||||
{
|
||||
return locate(key, F::hash(key, HASHSIZE) % HASHSIZE);
|
||||
}
|
||||
|
||||
public:
|
||||
bool add(C* value)
|
||||
{
|
||||
Entry** e = locate(KeyOfValue::generate(this, *value));
|
||||
if (*e)
|
||||
{
|
||||
return false; // sorry, duplicate
|
||||
}
|
||||
value->link(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
C* lookup(const K& key)
|
||||
{
|
||||
Entry** e = locate(key);
|
||||
return (*e) ? (*e)->get() : NULL;
|
||||
}
|
||||
|
||||
C* remove(const K& key)
|
||||
{
|
||||
Entry** e = locate(key);
|
||||
if (*e)
|
||||
{
|
||||
Entry* entry = *e;
|
||||
entry->unLink();
|
||||
return entry->get();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
// disable use of default operator=
|
||||
Hash& operator= (const Hash&);
|
||||
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
private:
|
||||
const Hash* hash;
|
||||
size_t elem;
|
||||
Entry* current;
|
||||
|
||||
iterator(const iterator& i);
|
||||
iterator& operator= (const iterator& i);
|
||||
|
||||
void next()
|
||||
{
|
||||
while(!current)
|
||||
{
|
||||
if (++elem >= HASHSIZE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
current = hash->data[elem];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit iterator(const Hash& h)
|
||||
: hash(&h), elem(0), current(hash->data[elem])
|
||||
{
|
||||
next();
|
||||
}
|
||||
|
||||
iterator& operator++()
|
||||
{
|
||||
if(hasData())
|
||||
{
|
||||
current = current->next();
|
||||
next();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool hasData() const
|
||||
{
|
||||
return current ? true : false;
|
||||
}
|
||||
|
||||
operator C*() const
|
||||
{
|
||||
fb_assert(hasData());
|
||||
return current->get();
|
||||
}
|
||||
|
||||
C* operator ->() const
|
||||
{
|
||||
fb_assert(hasData());
|
||||
return current->get();
|
||||
}
|
||||
|
||||
bool operator== (const iterator& h) const
|
||||
{
|
||||
return (hash == h.hash) && (elem == h.elem) && (current == h.current);
|
||||
}
|
||||
|
||||
bool operator!= (const iterator& h) const
|
||||
{
|
||||
return !(*this == h);
|
||||
}
|
||||
}; // class iterator
|
||||
|
||||
}; // class Hash
|
||||
|
||||
} // namespace Firebird
|
||||
|
||||
#endif // CLASSES_HASH_H
|
||||
|
721
src/jrd/dfw.epp
721
src/jrd/dfw.epp
@ -111,6 +111,8 @@
|
||||
#include "../jrd/IntlManager.h"
|
||||
#include "../common/utils_proto.h"
|
||||
|
||||
#include "../common/classes/Hash.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@ -132,6 +134,195 @@ DATABASE DB = FILENAME "ODS.RDB";
|
||||
|
||||
using namespace Jrd;
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
typedef Firebird::Hash<
|
||||
DeferredWork,
|
||||
Firebird::DefaultHash<DeferredWork>::DEFAULT_SIZE,
|
||||
DeferredWork,
|
||||
Firebird::DefaultKeyValue<DeferredWork>,
|
||||
DeferredWork
|
||||
> DfwHash;
|
||||
|
||||
class DeferredWork : public pool_alloc<type_dfw>,
|
||||
public DfwHash::Entry
|
||||
{
|
||||
private:
|
||||
DeferredWork(const DeferredWork&);
|
||||
|
||||
public:
|
||||
enum dfw_t dfw_type; // type of work deferred
|
||||
|
||||
private:
|
||||
DeferredWork*** dfw_end;
|
||||
DeferredWork** dfw_prev;
|
||||
DeferredWork* dfw_next;
|
||||
|
||||
public:
|
||||
Lock* dfw_lock; // relation creation lock
|
||||
Firebird::Array<DeferredWork*> dfw_args; // arguments
|
||||
SLONG dfw_sav_number; // save point number
|
||||
USHORT dfw_id; // object id, if appropriate
|
||||
USHORT dfw_count; // count of block posts
|
||||
Firebird::string dfw_name; // name of object
|
||||
|
||||
public:
|
||||
DeferredWork(MemoryPool& p, DeferredWork*** end,
|
||||
enum dfw_t t, USHORT id, SLONG sn, const Firebird::string& name)
|
||||
: dfw_type(t), dfw_end(end), dfw_prev(dfw_end ? *dfw_end : NULL),
|
||||
dfw_next(dfw_prev ? *dfw_prev : NULL), dfw_lock(NULL), dfw_args(p),
|
||||
dfw_sav_number(sn), dfw_id(id), dfw_count(1), dfw_name(p, name)
|
||||
{
|
||||
// make previous element point to us
|
||||
if (dfw_prev)
|
||||
{
|
||||
*dfw_prev = this;
|
||||
// make next element (if present) to point to us
|
||||
if (dfw_next)
|
||||
{
|
||||
dfw_next->dfw_prev = &dfw_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~DeferredWork()
|
||||
{
|
||||
// if we are linked
|
||||
if (dfw_prev)
|
||||
{
|
||||
if (dfw_next)
|
||||
{
|
||||
// adjust previous pointer in next element ...
|
||||
dfw_next->dfw_prev = dfw_prev;
|
||||
}
|
||||
// adjust next pointer in previous element
|
||||
*dfw_prev = dfw_next;
|
||||
|
||||
// Adjust end marker of the list
|
||||
if (*dfw_end == &dfw_next)
|
||||
{
|
||||
*dfw_end = dfw_prev;
|
||||
}
|
||||
}
|
||||
|
||||
for (DeferredWork** itr = dfw_args.begin(); itr < dfw_args.end(); ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
}
|
||||
|
||||
if (dfw_lock)
|
||||
{
|
||||
LCK_release(JRD_get_thread_data(), dfw_lock);
|
||||
delete dfw_lock;
|
||||
}
|
||||
}
|
||||
|
||||
DeferredWork* findArg(dfw_t type) const
|
||||
{
|
||||
for (DeferredWork* const* itr = dfw_args.begin(); itr < dfw_args.end(); ++itr)
|
||||
{
|
||||
DeferredWork* const arg = *itr;
|
||||
|
||||
if (arg->dfw_type == type)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DeferredWork** getNextPtr()
|
||||
{
|
||||
return &dfw_next;
|
||||
}
|
||||
|
||||
DeferredWork* getNext() const
|
||||
{
|
||||
return dfw_next;
|
||||
}
|
||||
|
||||
// hash interface
|
||||
bool isEqual(const DeferredWork& work)
|
||||
{
|
||||
if (dfw_type == work.dfw_type &&
|
||||
dfw_id == work.dfw_id &&
|
||||
dfw_name == work.dfw_name &&
|
||||
dfw_sav_number == work.dfw_sav_number)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DeferredWork* get() { return this; }
|
||||
|
||||
static size_t hash(const DeferredWork& work, size_t hashSize)
|
||||
{
|
||||
char key[sizeof work.dfw_type + sizeof work.dfw_id + 32];
|
||||
memset(key, 0, sizeof key);
|
||||
char* place = key;
|
||||
|
||||
memcpy(place, &work.dfw_type, sizeof work.dfw_type);
|
||||
place += sizeof work.dfw_type;
|
||||
|
||||
memcpy(place, &work.dfw_id, sizeof work.dfw_id);
|
||||
place += sizeof work.dfw_id;
|
||||
|
||||
work.dfw_name.copyTo(place, 32); // It's good enough to have first 32 bytes
|
||||
|
||||
return Firebird::DefaultHash<DeferredWork>::hash(key, sizeof key, hashSize);
|
||||
}
|
||||
};
|
||||
|
||||
class DfwSavePoint;
|
||||
|
||||
typedef Firebird::Hash<
|
||||
DfwSavePoint,
|
||||
Firebird::DefaultHash<DfwSavePoint>::DEFAULT_SIZE,
|
||||
SLONG,
|
||||
DfwSavePoint
|
||||
> DfwSavePointHash;
|
||||
|
||||
class DfwSavePoint : public DfwSavePointHash::Entry
|
||||
{
|
||||
SLONG dfw_sav_number;
|
||||
|
||||
public:
|
||||
DfwHash hash;
|
||||
|
||||
DfwSavePoint(SLONG number) : dfw_sav_number(number) { }
|
||||
|
||||
// hash interface
|
||||
bool isEqual(const SLONG& number)
|
||||
{
|
||||
if (dfw_sav_number == number)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DfwSavePoint* get() { return this; }
|
||||
|
||||
static SLONG generate(const void* /*sender*/, const DfwSavePoint& item)
|
||||
{
|
||||
return item.dfw_sav_number;
|
||||
}
|
||||
};
|
||||
|
||||
class DeferredJob
|
||||
{
|
||||
public:
|
||||
DfwSavePointHash hash;
|
||||
DeferredWork* work;
|
||||
DeferredWork** end;
|
||||
|
||||
DeferredJob() : work(0), end(&work) { }
|
||||
};
|
||||
|
||||
} // namespace Jrd
|
||||
|
||||
/*==================================================================
|
||||
**
|
||||
** NOTE:
|
||||
@ -174,6 +365,7 @@ static bool add_difference(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||
static bool delete_difference(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||
static bool begin_backup(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||
static bool end_backup(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||
static bool grant_privileges(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
@ -187,8 +379,6 @@ static void get_procedure_dependencies(DeferredWork*, bool);
|
||||
static void get_trigger_dependencies(DeferredWork*, bool);
|
||||
static void load_trigs(thread_db*, jrd_rel*, trig_vec**);
|
||||
static Format* make_format(thread_db*, jrd_rel*, USHORT *, TemporaryField*);
|
||||
static DeferredWork* post_work(jrd_tra*, SLONG, DeferredWork**, enum dfw_t,
|
||||
const dsc*, USHORT);
|
||||
static void put_summary_blob(blb*, enum rsr_t, bid*);
|
||||
static void put_summary_record(blb*, enum rsr_t, const UCHAR*, USHORT);
|
||||
static void setup_array(thread_db*, blb*, const TEXT*, USHORT, TemporaryField*);
|
||||
@ -198,6 +388,7 @@ static void setup_trigger_details(thread_db*, jrd_rel*, blb*, trig_vec**, const
|
||||
static bool validate_text_type (thread_db*, const TemporaryField*);
|
||||
|
||||
static void check_partners(thread_db*, const USHORT);
|
||||
static Firebird::string get_string(const dsc* desc);
|
||||
|
||||
static const UCHAR nonnull_validation_blr[] =
|
||||
{
|
||||
@ -234,7 +425,7 @@ static const deferred_task task_table[] =
|
||||
{ dfw_compute_security, compute_security },
|
||||
{ dfw_create_index, modify_index },
|
||||
{ dfw_create_expression_index, modify_index },
|
||||
{ dfw_grant, GRANT_privileges },
|
||||
{ dfw_grant, grant_privileges },
|
||||
{ dfw_create_trigger, create_trigger },
|
||||
{ dfw_delete_trigger, delete_trigger },
|
||||
{ dfw_modify_trigger, modify_trigger },
|
||||
@ -256,7 +447,7 @@ static const deferred_task task_table[] =
|
||||
};
|
||||
|
||||
|
||||
USHORT DFW_assign_index_type(DeferredWork* work, SSHORT field_type, SSHORT ttype)
|
||||
USHORT DFW_assign_index_type(const Firebird::string& name, SSHORT field_type, SSHORT ttype)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -297,7 +488,7 @@ USHORT DFW_assign_index_type(DeferredWork* work, SSHORT field_type, SSHORT ttype
|
||||
|
||||
ERR_post_nothrow(isc_no_meta_update,
|
||||
isc_arg_gds, isc_random, isc_arg_string,
|
||||
ERR_cstring(work->dfw_name), isc_arg_end);
|
||||
ERR_cstring(name), isc_arg_end);
|
||||
INTL_texttype_lookup(tdbb, ttype); // should punt
|
||||
ERR_punt(); // if INTL_texttype_lookup hasn't punt
|
||||
}
|
||||
@ -337,30 +528,33 @@ void DFW_delete_deferred( jrd_tra* transaction, SLONG sav_number)
|
||||
|
||||
/* If there is no deferred work, just return */
|
||||
|
||||
if (!transaction->tra_deferred_work) {
|
||||
if (!transaction->tra_deferred_job) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remove deferred work and events which are to be rolled back */
|
||||
bool deferred_meta = false;
|
||||
DeferredWork* work;
|
||||
for (DeferredWork** ptr = &transaction->tra_deferred_work; (work = *ptr);)
|
||||
if (sav_number == -1)
|
||||
{
|
||||
if ((work->dfw_sav_number == sav_number) || (sav_number == -1))
|
||||
DeferredWork* work;
|
||||
while (work = transaction->tra_deferred_job->work)
|
||||
{
|
||||
*ptr = work->dfw_next;
|
||||
delete work;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = &(*ptr)->dfw_next;
|
||||
if (work->dfw_type != dfw_post_event)
|
||||
deferred_meta = true;
|
||||
}
|
||||
transaction->tra_flags &= ~TRA_deferred_meta;
|
||||
return;
|
||||
}
|
||||
|
||||
DfwSavePoint* h = transaction->tra_deferred_job->hash.lookup(sav_number);
|
||||
if (!h)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!deferred_meta) {
|
||||
transaction->tra_flags &= ~TRA_deferred_meta;
|
||||
for (DfwHash::iterator i(h->hash); i.hasData();)
|
||||
{
|
||||
DeferredWork* work(i);
|
||||
++i;
|
||||
delete work;
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,52 +577,49 @@ void DFW_merge_work(jrd_tra* transaction,
|
||||
|
||||
/* If there is no deferred work, just return */
|
||||
|
||||
if (!transaction->tra_deferred_work)
|
||||
if (!transaction->tra_deferred_job)
|
||||
return;
|
||||
|
||||
/* Decrement the save point number in the deferred block
|
||||
* i.e. merge with the previous level.
|
||||
*/
|
||||
DeferredWork* work;
|
||||
for (DeferredWork** ptr = &transaction->tra_deferred_work; (work = *ptr);)
|
||||
|
||||
DeferredJob* job = transaction->tra_deferred_job;
|
||||
|
||||
// Check to see if work is already posted
|
||||
|
||||
DfwSavePoint* oldSp = job->hash.lookup(old_sav_number);
|
||||
if (!oldSp)
|
||||
{
|
||||
if (work->dfw_sav_number == old_sav_number)
|
||||
return;
|
||||
}
|
||||
|
||||
DfwSavePoint* newSp = job->hash.lookup(new_sav_number);
|
||||
|
||||
// Decrement the save point number in the deferred block
|
||||
// i.e. merge with the previous level.
|
||||
|
||||
|
||||
for (DfwHash::iterator itr(oldSp->hash); itr.hasData();)
|
||||
{
|
||||
if (! newSp)
|
||||
{
|
||||
work->dfw_sav_number = new_sav_number;
|
||||
|
||||
/* merge this entry with other identical entries at
|
||||
* same save point level. Start from the beginning and
|
||||
* stop with the that is being merged.
|
||||
*/
|
||||
DeferredWork* work_m;
|
||||
for (DeferredWork** ptr_m = &transaction->tra_deferred_work;
|
||||
((work_m = *ptr_m) && (work_m != work));
|
||||
ptr_m = &(*ptr_m)->dfw_next)
|
||||
{
|
||||
if (work_m->dfw_type == work->dfw_type &&
|
||||
work_m->dfw_id == work->dfw_id &&
|
||||
work_m->dfw_name == work->dfw_name &&
|
||||
work_m->dfw_sav_number == work->dfw_sav_number)
|
||||
{
|
||||
/* Yes! There is a duplicate entry. Take out the
|
||||
* entry for which the save point was decremented
|
||||
*/
|
||||
|
||||
*ptr = work->dfw_next;
|
||||
|
||||
if (work_m->dfw_name.length()) {
|
||||
work_m->dfw_count += work->dfw_count;
|
||||
}
|
||||
|
||||
delete work;
|
||||
work = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
newSp = FB_NEW(*transaction->tra_pool) DfwSavePoint(new_sav_number);
|
||||
job->hash.add(newSp);
|
||||
}
|
||||
|
||||
if (work) {
|
||||
ptr = &(*ptr)->dfw_next;
|
||||
DeferredWork* work(itr);
|
||||
++itr;
|
||||
oldSp->hash.remove(*work); // After ++itr
|
||||
work->dfw_sav_number = new_sav_number;
|
||||
|
||||
if (!newSp->hash.lookup(*work))
|
||||
{
|
||||
newSp->hash.add(work);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete work;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -476,7 +667,7 @@ void DFW_perform_work(jrd_tra* transaction)
|
||||
/* If no deferred work or it's all deferred event posting
|
||||
don't bother */
|
||||
|
||||
if (!transaction->tra_deferred_work ||
|
||||
if (!transaction->tra_deferred_job ||
|
||||
!(transaction->tra_flags & TRA_deferred_meta))
|
||||
{
|
||||
return;
|
||||
@ -504,9 +695,9 @@ void DFW_perform_work(jrd_tra* transaction)
|
||||
for (const deferred_task* task = task_table;
|
||||
task->task_type != dfw_null; ++task)
|
||||
{
|
||||
for (DeferredWork* work = transaction->tra_deferred_work;
|
||||
work;
|
||||
work = work->dfw_next)
|
||||
for (DeferredWork* work = transaction->tra_deferred_job->work;
|
||||
work;
|
||||
work = work->getNext())
|
||||
{
|
||||
if (work->dfw_type == task->task_type)
|
||||
{
|
||||
@ -550,18 +741,20 @@ void DFW_perform_work(jrd_tra* transaction)
|
||||
commit retaining transactions don't re-execute them. Leave
|
||||
events to be posted after commit */
|
||||
|
||||
DeferredWork* work;
|
||||
for (DeferredWork** ptr = &transaction->tra_deferred_work; (work = *ptr);)
|
||||
for (DeferredWork* itr = transaction->tra_deferred_job->work; itr;)
|
||||
{
|
||||
if ((work->dfw_type == dfw_post_event) ||
|
||||
(work->dfw_type == dfw_delete_shadow))
|
||||
DeferredWork* work = itr;
|
||||
itr = itr->getNext();
|
||||
|
||||
switch (work->dfw_type)
|
||||
{
|
||||
ptr = &(*ptr)->dfw_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = work->dfw_next;
|
||||
case dfw_post_event:
|
||||
case dfw_delete_shadow:
|
||||
break;
|
||||
|
||||
default:
|
||||
delete work;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -591,7 +784,7 @@ void DFW_perform_post_commit_work(jrd_tra* transaction)
|
||||
**************************************/
|
||||
ISC_STATUS_ARRAY status;
|
||||
|
||||
if (!transaction->tra_deferred_work)
|
||||
if (!transaction->tra_deferred_job)
|
||||
return;
|
||||
|
||||
bool pending_events = false;
|
||||
@ -599,9 +792,11 @@ void DFW_perform_post_commit_work(jrd_tra* transaction)
|
||||
Database* dbb = GET_DBB();
|
||||
Lock* lock = dbb->dbb_lock;
|
||||
|
||||
DeferredWork* work;
|
||||
for (DeferredWork** ptr = &transaction->tra_deferred_work; (work = *ptr);)
|
||||
for (DeferredWork* itr = transaction->tra_deferred_job->work; itr;)
|
||||
{
|
||||
DeferredWork* work = itr;
|
||||
itr = itr->getNext();
|
||||
|
||||
if (work->dfw_type == dfw_post_event)
|
||||
{
|
||||
EVENT_post( status,
|
||||
@ -610,20 +805,14 @@ void DFW_perform_post_commit_work(jrd_tra* transaction)
|
||||
work->dfw_name.length(),
|
||||
work->dfw_name.c_str(),
|
||||
work->dfw_count);
|
||||
*ptr = work->dfw_next;
|
||||
delete work;
|
||||
pending_events = true;
|
||||
}
|
||||
else if (work->dfw_type == dfw_delete_shadow)
|
||||
{
|
||||
unlink(work->dfw_name.c_str());
|
||||
*ptr = work->dfw_next;
|
||||
delete work;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = &(*ptr)->dfw_next;
|
||||
}
|
||||
}
|
||||
|
||||
if (pending_events)
|
||||
@ -667,19 +856,50 @@ DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const dsc* de
|
||||
*
|
||||
**************************************/
|
||||
|
||||
/* get the current save point number */
|
||||
// get the current save point number
|
||||
|
||||
const SLONG sav_number = transaction->tra_save_point ?
|
||||
transaction->tra_save_point->sav_number : 0;
|
||||
|
||||
/* post work */
|
||||
// initialize transaction if needed
|
||||
|
||||
return post_work(transaction,
|
||||
sav_number,
|
||||
&transaction->tra_deferred_work,
|
||||
type,
|
||||
desc,
|
||||
id);
|
||||
DeferredJob *job = transaction->tra_deferred_job;
|
||||
if (! job)
|
||||
{
|
||||
transaction->tra_deferred_job = job = FB_NEW(*transaction->tra_pool) DeferredJob;
|
||||
}
|
||||
|
||||
// Check to see if work is already posted
|
||||
|
||||
DfwSavePoint* sp = job->hash.lookup(sav_number);
|
||||
if (! sp)
|
||||
{
|
||||
sp = FB_NEW(*transaction->tra_pool) DfwSavePoint(sav_number);
|
||||
job->hash.add(sp);
|
||||
}
|
||||
|
||||
const Firebird::string name = get_string(desc);
|
||||
DeferredWork tmp(Firebird::AutoStorage::getAutoMemoryPool(), 0, type, id, sav_number, name);
|
||||
DeferredWork* work = sp->hash.lookup(tmp);
|
||||
if (work)
|
||||
{
|
||||
return work;
|
||||
}
|
||||
|
||||
// Not already posted, so do so now.
|
||||
|
||||
work = FB_NEW(*transaction->tra_pool)
|
||||
DeferredWork(*transaction->tra_pool, &(job->end), type, id, sav_number, name);
|
||||
job->end = work->getNextPtr();
|
||||
fb_assert(!(*job->end));
|
||||
sp->hash.add(work);
|
||||
|
||||
if (type != dfw_post_event)
|
||||
transaction->tra_flags |= TRA_deferred_meta;
|
||||
else if (transaction->tra_save_point)
|
||||
transaction->tra_save_point->sav_flags |= SAV_event_post;
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
|
||||
@ -697,12 +917,35 @@ DeferredWork* DFW_post_work_arg( jrd_tra* transaction, DeferredWork* work, const
|
||||
*
|
||||
**************************************/
|
||||
|
||||
return post_work(transaction,
|
||||
work->dfw_sav_number,
|
||||
&work->dfw_args,
|
||||
work->dfw_type,
|
||||
desc,
|
||||
id);
|
||||
return DFW_post_work_arg(transaction, work, desc, id, work->dfw_type);
|
||||
}
|
||||
|
||||
|
||||
DeferredWork* DFW_post_work_arg( jrd_tra* transaction, DeferredWork* work, const dsc* desc,
|
||||
USHORT id, Jrd::dfw_t type)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* D F W _ p o s t _ w o r k _ a r g
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Post an argument for work to be deferred to commit time.
|
||||
*
|
||||
**************************************/
|
||||
const Firebird::string name = get_string(desc);
|
||||
|
||||
DeferredWork* arg = work->findArg(type);
|
||||
|
||||
if (! arg)
|
||||
{
|
||||
arg = FB_NEW(*transaction->tra_pool)
|
||||
DeferredWork(*transaction->tra_pool, 0, type, id, 0, name);
|
||||
work->dfw_args.add(arg);
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
@ -1245,6 +1488,65 @@ static bool end_backup( thread_db* tdbb,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool grant_privileges(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* g r a n t _ p r i v i l e g e s
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Compute access control list from SQL privileges.
|
||||
*
|
||||
**************************************/
|
||||
switch (phase)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
return true;
|
||||
|
||||
case 3:
|
||||
GRANT_privileges(tdbb, work->dfw_name, work->dfw_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* c r e a t e _ e x p r e s s i o n _ i n d e x
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Create a new expression index.
|
||||
*
|
||||
**************************************/
|
||||
switch (phase)
|
||||
{
|
||||
case 0:
|
||||
MET_delete_dependencies(tdbb, work->dfw_name, obj_expression_index);
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
return true;
|
||||
|
||||
case 3:
|
||||
PCMET_expression_index(tdbb, work->dfw_name, work->dfw_id, transaction);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void check_dependencies(thread_db* tdbb,
|
||||
const TEXT* dpdo_name,
|
||||
const TEXT* field_name,
|
||||
@ -1553,7 +1855,7 @@ static bool modify_index( thread_db* tdbb,
|
||||
break;
|
||||
|
||||
case dfw_create_expression_index :
|
||||
task_routine = PCMET_expression_index;
|
||||
task_routine = create_expression_index;
|
||||
break;
|
||||
|
||||
case dfw_delete_index :
|
||||
@ -1873,7 +2175,7 @@ static bool create_index( thread_db* tdbb,
|
||||
const SSHORT text_type =
|
||||
INTL_CS_COLL_TO_TTYPE(FLD.RDB$CHARACTER_SET_ID, collate);
|
||||
idx.idx_rpt[SEG.RDB$FIELD_POSITION].idx_itype =
|
||||
DFW_assign_index_type(work,
|
||||
DFW_assign_index_type(work->dfw_name,
|
||||
gds_cvt_blr_dtype[FLD.RDB$FIELD_TYPE],
|
||||
text_type);
|
||||
|
||||
@ -2063,13 +2365,10 @@ static bool create_procedure( thread_db* tdbb,
|
||||
|
||||
case 3:
|
||||
{
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_check_blr))
|
||||
arg = arg->dfw_next;
|
||||
const bool compile = !work->findArg(dfw_arg_check_blr);
|
||||
get_procedure_dependencies(work, compile);
|
||||
|
||||
get_procedure_dependencies(work, arg == NULL);
|
||||
|
||||
jrd_prc* procedure = MET_lookup_procedure(tdbb, work->dfw_name, (arg ? false : true));
|
||||
jrd_prc* procedure = MET_lookup_procedure(tdbb, work->dfw_name, compile);
|
||||
if (!procedure) {
|
||||
return false;
|
||||
}
|
||||
@ -2294,26 +2593,16 @@ static bool create_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
|
||||
case 3:
|
||||
{
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_check_blr))
|
||||
arg = arg->dfw_next;
|
||||
|
||||
get_trigger_dependencies(work, arg == NULL);
|
||||
const bool compile = !work->findArg(dfw_arg_check_blr);
|
||||
get_trigger_dependencies(work, compile);
|
||||
return true;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_rel_name))
|
||||
arg = arg->dfw_next;
|
||||
|
||||
if (!arg)
|
||||
if (!work->findArg(dfw_arg_rel_name))
|
||||
{
|
||||
arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_trg_type))
|
||||
arg = arg->dfw_next;
|
||||
|
||||
const DeferredWork* const arg = work->findArg(dfw_arg_trg_type);
|
||||
fb_assert(arg);
|
||||
|
||||
if (arg && (arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DB)
|
||||
@ -2961,9 +3250,7 @@ static bool delete_index(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_index_name))
|
||||
arg = arg->dfw_next;
|
||||
const DeferredWork* arg = work->findArg(dfw_arg_index_name);
|
||||
|
||||
fb_assert(arg);
|
||||
const USHORT id = arg->dfw_id - 1;
|
||||
@ -3070,11 +3357,7 @@ static bool delete_index(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
|
||||
// if index was bound to deleted FK constraint
|
||||
// then work->dfw_args was set in VIO_erase
|
||||
arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_partner_rel_id))
|
||||
{
|
||||
arg = arg->dfw_next;
|
||||
}
|
||||
arg = work->findArg(dfw_arg_partner_rel_id);
|
||||
|
||||
if (arg) {
|
||||
if (arg->dfw_id) {
|
||||
@ -3742,16 +4025,11 @@ static bool delete_trigger( thread_db* tdbb,
|
||||
|
||||
case 4:
|
||||
{
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_rel_name))
|
||||
arg = arg->dfw_next;
|
||||
const DeferredWork* arg = work->findArg(dfw_arg_rel_name);
|
||||
|
||||
if (!arg)
|
||||
{
|
||||
arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_trg_type))
|
||||
arg = arg->dfw_next;
|
||||
|
||||
arg = work->findArg(dfw_arg_trg_type);
|
||||
fb_assert(arg);
|
||||
|
||||
if (arg && (arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DB)
|
||||
@ -3819,8 +4097,7 @@ static bool find_depend_in_dfw( thread_db* tdbb,
|
||||
|
||||
/* Look to see if an object of the desired type is being deleted. */
|
||||
|
||||
for (const DeferredWork* work = transaction->tra_deferred_work; work;
|
||||
work = work->dfw_next)
|
||||
for (const DeferredWork* work = transaction->tra_deferred_job->work; work; work = work->getNext())
|
||||
{
|
||||
if ((work->dfw_type == dfw_type ||
|
||||
(work->dfw_type == dfw_modify_procedure && dfw_type == dfw_delete_procedure)) &&
|
||||
@ -3830,11 +4107,7 @@ static bool find_depend_in_dfw( thread_db* tdbb,
|
||||
if (work->dfw_type == dfw_modify_procedure)
|
||||
{
|
||||
// Don't consider that procedure is in DFW if we are only checking the BLR
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_check_blr))
|
||||
arg = arg->dfw_next;
|
||||
|
||||
if (!arg)
|
||||
if (!work->findArg(dfw_arg_check_blr))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -3844,15 +4117,14 @@ static bool find_depend_in_dfw( thread_db* tdbb,
|
||||
if (work->dfw_type == dfw_type &&
|
||||
dfw_type == dfw_delete_expression_index)
|
||||
{
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg)
|
||||
for (size_t i = 0; i < work->dfw_args.getCount(); ++i)
|
||||
{
|
||||
DeferredWork* arg = work->dfw_args[i];
|
||||
if (arg->dfw_type == dfw_arg_index_name &&
|
||||
arg->dfw_name == object_name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
arg = arg->dfw_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4600,11 +4872,8 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
MET_delete_dependencies(tdbb, work->dfw_name, obj_view);
|
||||
|
||||
{ // begin scope
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_force_computed))
|
||||
arg = arg->dfw_next;
|
||||
|
||||
if (arg && arg->dfw_type == dfw_arg_force_computed)
|
||||
const DeferredWork* arg = work->findArg(dfw_arg_force_computed);
|
||||
if (arg)
|
||||
{
|
||||
computed_field = true;
|
||||
MET_delete_dependencies(tdbb, arg->dfw_name, obj_computed);
|
||||
@ -4807,11 +5076,9 @@ static bool modify_procedure( thread_db* tdbb,
|
||||
MET_remove_procedure(tdbb, work->dfw_id, NULL);
|
||||
|
||||
/* Now handle the new definition */
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_check_blr))
|
||||
arg = arg->dfw_next;
|
||||
bool compile = !work->findArg(dfw_arg_check_blr);
|
||||
|
||||
get_procedure_dependencies(work, arg == NULL);
|
||||
get_procedure_dependencies(work, compile);
|
||||
|
||||
procedure->prc_flags &= ~(PRC_obsolete | PRC_being_altered);
|
||||
|
||||
@ -4834,11 +5101,9 @@ static bool modify_procedure( thread_db* tdbb,
|
||||
case 5:
|
||||
if (ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_original) >= ODS_11_1)
|
||||
{
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_check_blr))
|
||||
arg = arg->dfw_next;
|
||||
const DeferredWork* arg = work->findArg(dfw_arg_check_blr);
|
||||
|
||||
if (arg && arg->dfw_type == dfw_arg_check_blr)
|
||||
if (arg)
|
||||
{
|
||||
SSHORT valid_blr = FALSE;
|
||||
|
||||
@ -4908,28 +5173,21 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
|
||||
case 3:
|
||||
{
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_check_blr))
|
||||
arg = arg->dfw_next;
|
||||
bool compile = !work->findArg(dfw_arg_check_blr);
|
||||
|
||||
/* get rid of old dependencies, bring in the new */
|
||||
MET_delete_dependencies(tdbb, work->dfw_name, obj_trigger);
|
||||
get_trigger_dependencies(work, arg == NULL);
|
||||
get_trigger_dependencies(work, compile);
|
||||
}
|
||||
return true;
|
||||
|
||||
case 4:
|
||||
{
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_rel_name))
|
||||
arg = arg->dfw_next;
|
||||
const DeferredWork* arg = work->findArg(dfw_arg_rel_name);
|
||||
|
||||
if (!arg)
|
||||
{
|
||||
arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_trg_type))
|
||||
arg = arg->dfw_next;
|
||||
|
||||
arg = work->findArg(dfw_arg_trg_type);
|
||||
fb_assert(arg);
|
||||
|
||||
if (arg && (arg->dfw_id & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DB)
|
||||
@ -4946,9 +5204,7 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
|
||||
if (ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_original) >= ODS_11_1)
|
||||
{
|
||||
const DeferredWork* arg = work->dfw_args;
|
||||
while (arg && (arg->dfw_type != dfw_arg_check_blr))
|
||||
arg = arg->dfw_next;
|
||||
const DeferredWork* arg = work->findArg(dfw_arg_check_blr);
|
||||
|
||||
if (arg)
|
||||
{
|
||||
@ -5030,97 +5286,6 @@ static bool modify_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
}
|
||||
|
||||
|
||||
static DeferredWork* post_work(jrd_tra* transaction,
|
||||
SLONG sav_number,
|
||||
DeferredWork** list,
|
||||
enum dfw_t type,
|
||||
const dsc* desc,
|
||||
USHORT id)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p o s t _ w o r k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Post a piece of work to be deferred to commit time.
|
||||
* If we already know about it, so much the better.
|
||||
*
|
||||
**************************************/
|
||||
const char* string;
|
||||
USHORT length;
|
||||
TEXT temp[MAXPATHLEN]; // Must hold largest metadata field or filename
|
||||
|
||||
if (!desc)
|
||||
{
|
||||
string = NULL;
|
||||
length = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Find the actual length of the string, searching until the claimed
|
||||
end of the string, or the terminating \0, whichever comes first. */
|
||||
|
||||
length = MOV_make_string(desc,
|
||||
ttype_metadata,
|
||||
&string,
|
||||
(vary*)temp,
|
||||
sizeof(temp));
|
||||
|
||||
const char* p = string;
|
||||
const char* const q = string + length;
|
||||
while (p < q && *p)
|
||||
{
|
||||
++p;
|
||||
}
|
||||
|
||||
// Trim trailing blanks (bug 3355)
|
||||
|
||||
while (--p >= string && *p == ' ')
|
||||
;
|
||||
length = (p + 1) - string;
|
||||
}
|
||||
|
||||
DeferredWork* work;
|
||||
DeferredWork** ptr;
|
||||
|
||||
// Check to see if work is already posted
|
||||
|
||||
for (ptr = list; (work = *ptr); ptr = &(*ptr)->dfw_next)
|
||||
{
|
||||
if (work->dfw_type == type &&
|
||||
work->dfw_id == id &&
|
||||
work->dfw_name.length() == length &&
|
||||
work->dfw_sav_number == sav_number)
|
||||
{
|
||||
if (!length)
|
||||
return *ptr;
|
||||
if (!memcmp(string, work->dfw_name.c_str(), length)) {
|
||||
++work->dfw_count;
|
||||
return *ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not already posted, so do so now.
|
||||
|
||||
*ptr = work = FB_NEW(*transaction->tra_pool) DeferredWork(*transaction->tra_pool);
|
||||
work->dfw_type = type;
|
||||
work->dfw_id = id;
|
||||
work->dfw_count = 1;
|
||||
work->dfw_sav_number = sav_number;
|
||||
work->dfw_name.assign(string, length);
|
||||
|
||||
if (type != dfw_post_event)
|
||||
transaction->tra_flags |= TRA_deferred_meta;
|
||||
else if (transaction->tra_save_point)
|
||||
transaction->tra_save_point->sav_flags |= SAV_event_post;
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
|
||||
static void put_summary_blob(blb* blob, RSR_T type, bid* blob_id)
|
||||
{
|
||||
/**************************************
|
||||
@ -5545,3 +5710,45 @@ static bool validate_text_type(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Firebird::string get_string(const dsc* desc)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
*g e t _ s t r i n g
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
*Get string for a given descriptor.
|
||||
*
|
||||
**************************************/
|
||||
const char* str;
|
||||
TEXT temp[MAXPATHLEN]; // Must hold largest metadata field or filename
|
||||
|
||||
if (!desc)
|
||||
{
|
||||
return Firebird::string();
|
||||
}
|
||||
|
||||
// Find the actual length of the string, searching until the claimed
|
||||
// end of the string, or the terminating \0, whichever comes first
|
||||
|
||||
USHORT length = MOV_make_string(desc, ttype_metadata, &str, (vary*)temp, sizeof(temp));
|
||||
|
||||
const char* p = str;
|
||||
const char* const q = str + length;
|
||||
while (p < q && *p)
|
||||
{
|
||||
++p;
|
||||
}
|
||||
|
||||
// Trim trailing blanks (bug 3355)
|
||||
|
||||
while (--p >= str && *p == ' ')
|
||||
;
|
||||
length = (p + 1) - str;
|
||||
|
||||
return Firebird::string(str, length);
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,12 @@
|
||||
#ifndef JRD_DFW_PROTO_H
|
||||
#define JRD_DFW_PROTO_H
|
||||
|
||||
USHORT DFW_assign_index_type(Jrd::DeferredWork*, SSHORT, SSHORT);
|
||||
namespace Jrd
|
||||
{
|
||||
class DeferredWork;
|
||||
}
|
||||
|
||||
USHORT DFW_assign_index_type(const Firebird::string&, SSHORT, SSHORT);
|
||||
void DFW_delete_deferred(Jrd::jrd_tra*, SLONG);
|
||||
void DFW_merge_work(Jrd::jrd_tra*, SLONG, SLONG);
|
||||
void DFW_perform_system_work(Jrd::thread_db*);
|
||||
@ -33,6 +38,7 @@ void DFW_perform_post_commit_work(Jrd::jrd_tra*);
|
||||
Jrd::DeferredWork* DFW_post_system_work(Jrd::thread_db*, enum Jrd::dfw_t, const dsc*, USHORT);
|
||||
Jrd::DeferredWork* DFW_post_work(Jrd::jrd_tra*, enum Jrd::dfw_t, const dsc*, USHORT);
|
||||
Jrd::DeferredWork* DFW_post_work_arg(Jrd::jrd_tra*, Jrd::DeferredWork*, const dsc*, USHORT);
|
||||
Jrd::DeferredWork* DFW_post_work_arg(Jrd::jrd_tra*, Jrd::DeferredWork*, const dsc*, USHORT, Jrd::dfw_t);
|
||||
void DFW_update_index(const TEXT*, USHORT, const Jrd::SelectivityList&);
|
||||
|
||||
Jrd::Lock* DFW_protect_relation(Jrd::thread_db*, Jrd::jrd_tra*, Jrd::jrd_rel*, bool&);
|
||||
|
@ -95,9 +95,7 @@ static SecurityClass::flags_t trans_sql_priv(const TEXT*);
|
||||
static SecurityClass::flags_t squeeze_acl(Acl&, const Firebird::MetaName&, SSHORT);
|
||||
static bool check_string(const UCHAR*, const Firebird::MetaName&);
|
||||
|
||||
|
||||
bool GRANT_privileges( thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
jrd_tra*) // unused param, makes dfw.epp happy
|
||||
void GRANT_privileges(thread_db* tdbb, const Firebird::string& name, USHORT id)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -113,88 +111,70 @@ bool GRANT_privileges( thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
*
|
||||
**************************************/
|
||||
|
||||
switch (phase) {
|
||||
case 1:
|
||||
case 2:
|
||||
return true;
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
case 3:
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
bool restrct = false;
|
||||
|
||||
bool restrct = false;
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Firebird::MetaName s_class, owner, default_class;
|
||||
bool view; // unused after being retrieved.
|
||||
get_object_info(tdbb, name.c_str(), id, owner, s_class, default_class, view);
|
||||
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
Firebird::MetaName s_class, owner, default_class;
|
||||
bool view; // unused after being retrieved.
|
||||
get_object_info(tdbb, work->dfw_name.c_str(), work->dfw_id, owner,
|
||||
s_class, default_class, view);
|
||||
if (s_class.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_class.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
/* start the acl off by giving the owner all privileges */
|
||||
|
||||
/* start the acl off by giving the owner all privileges */
|
||||
Acl acl, default_acl;
|
||||
|
||||
Acl acl, default_acl;
|
||||
CHECK_AND_MOVE(acl, ACL_version);
|
||||
grant_user(acl, owner, obj_user,
|
||||
(id == obj_procedure ? SCL_execute | OWNER_PRIVS : OWNER_PRIVS));
|
||||
|
||||
CHECK_AND_MOVE(acl, ACL_version);
|
||||
grant_user(acl, owner, obj_user,
|
||||
((work->dfw_id == obj_procedure) ? (SCL_execute | OWNER_PRIVS) : OWNER_PRIVS));
|
||||
/* Pick up any relation-level privileges */
|
||||
|
||||
/* Pick up any relation-level privileges */
|
||||
const SecurityClass::flags_t public_priv = get_public_privs(tdbb, name.c_str(), id);
|
||||
get_user_privs(tdbb, acl, name.c_str(), id, owner, public_priv);
|
||||
|
||||
const SecurityClass::flags_t public_priv =
|
||||
get_public_privs(tdbb, work->dfw_name.c_str(), work->dfw_id);
|
||||
get_user_privs(tdbb, acl, work->dfw_name.c_str(), work->dfw_id, owner, public_priv);
|
||||
if (id == obj_relation)
|
||||
{
|
||||
default_acl.assign(acl);
|
||||
|
||||
if (work->dfw_id == obj_relation)
|
||||
{
|
||||
default_acl.assign(acl);
|
||||
const SecurityClass::flags_t aggregate_public =
|
||||
save_field_privileges(tdbb, acl, name.c_str(), owner, public_priv);
|
||||
|
||||
const SecurityClass::flags_t aggregate_public =
|
||||
save_field_privileges(tdbb, acl, work->dfw_name.c_str(), owner, public_priv);
|
||||
|
||||
/* SQL tables don't need the 'all priviliges to all views' acl anymore.
|
||||
This special acl was only generated for SQL. */
|
||||
/* SQL tables don't need the 'all priviliges to all views' acl anymore.
|
||||
This special acl was only generated for SQL. */
|
||||
#ifdef NOT_USED_OR_REPLACED
|
||||
/* grant_views (&acl, VIEW_PRIVS); */
|
||||
/* grant_views (&acl, VIEW_PRIVS); */
|
||||
#endif
|
||||
|
||||
/* finish off and store the security class for the relation */
|
||||
/* finish off and store the security class for the relation */
|
||||
|
||||
finish_security_class(acl, aggregate_public);
|
||||
finish_security_class(acl, aggregate_public);
|
||||
|
||||
save_security_class(tdbb, s_class, acl);
|
||||
save_security_class(tdbb, s_class, acl);
|
||||
|
||||
if (acl.getCount() != default_acl.getCount()) /* relation privs were added? */
|
||||
restrct = true;
|
||||
if (acl.getCount() != default_acl.getCount()) /* relation privs were added? */
|
||||
restrct = true;
|
||||
|
||||
/* if there have been privileges added at the relation level which
|
||||
need to be restricted from other fields in the relation,
|
||||
update the acl for them */
|
||||
/* if there have been privileges added at the relation level which
|
||||
need to be restricted from other fields in the relation,
|
||||
update the acl for them */
|
||||
|
||||
if (restrct)
|
||||
{
|
||||
finish_security_class(default_acl, public_priv);
|
||||
define_default_class(tdbb, work->dfw_name.c_str(), default_class, default_acl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
finish_security_class(acl, public_priv);
|
||||
save_security_class(tdbb, s_class, acl);
|
||||
}
|
||||
|
||||
break;
|
||||
if (restrct)
|
||||
{
|
||||
finish_security_class(default_acl, public_priv);
|
||||
define_default_class(tdbb, name.c_str(), default_class, default_acl);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
else {
|
||||
finish_security_class(acl, public_priv);
|
||||
save_security_class(tdbb, s_class, acl);
|
||||
}
|
||||
|
||||
DFW_perform_system_work(tdbb);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,11 +24,11 @@
|
||||
#ifndef JRD_GRANT_PROTO_H
|
||||
#define JRD_GRANT_PROTO_H
|
||||
|
||||
#include "../common/classes/array.h"
|
||||
#include "../common/classes/fb_string.h"
|
||||
|
||||
class Jrd::DeferredWork;
|
||||
|
||||
bool GRANT_privileges(Jrd::thread_db*, SSHORT, Jrd::DeferredWork*, Jrd::jrd_tra*);
|
||||
void GRANT_privileges(Jrd::thread_db*, const Firebird::string&, USHORT);
|
||||
|
||||
#endif // JRD_GRANT_PROTO_H
|
||||
|
||||
|
@ -803,7 +803,7 @@ DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc
|
||||
|
||||
DeferredWork* dw2 =
|
||||
DFW_post_work(transaction, dfw_modify_procedure, &desc, PRC.RDB$PROCEDURE_ID);
|
||||
DFW_post_work_arg(transaction, dw2, NULL, 0)->dfw_type = dfw_arg_check_blr;
|
||||
DFW_post_work_arg(transaction, dw2, NULL, 0, dfw_arg_check_blr);
|
||||
END_FOR;
|
||||
|
||||
if (!REQUEST(irq_m_fields2))
|
||||
@ -836,7 +836,7 @@ DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc
|
||||
|
||||
desc.dsc_length = trigger_relation_name.length();
|
||||
desc.dsc_address = (UCHAR*) trigger_relation_name.c_str();
|
||||
DFW_post_work_arg(transaction, dw2, &desc, 0)->dfw_type = dfw_arg_check_blr;
|
||||
DFW_post_work_arg(transaction, dw2, &desc, 0, dfw_arg_check_blr);
|
||||
END_FOR;
|
||||
|
||||
if (!REQUEST(irq_m_fields3))
|
||||
|
@ -55,8 +55,8 @@ using namespace Jrd;
|
||||
DATABASE DB = FILENAME "ODS.RDB";
|
||||
|
||||
|
||||
bool PCMET_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
jrd_tra* transaction)
|
||||
void PCMET_expression_index(thread_db* tdbb, const Firebird::string& name,
|
||||
USHORT id, jrd_tra* transaction)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -77,117 +77,21 @@ bool PCMET_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
SET_TDBB(tdbb);
|
||||
const Database* dbb = tdbb->getDatabase();
|
||||
|
||||
switch (phase)
|
||||
{
|
||||
case 0:
|
||||
MET_delete_dependencies(tdbb, work->dfw_name, obj_expression_index);
|
||||
return false;
|
||||
relation = NULL;
|
||||
MOVE_CLEAR(&idx, sizeof(index_desc));
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
return true;
|
||||
|
||||
case 3:
|
||||
|
||||
relation = NULL;
|
||||
MOVE_CLEAR(&idx, sizeof(index_desc));
|
||||
|
||||
request = CMP_find_request(tdbb, irq_c_exp_index, IRQ_REQUESTS);
|
||||
request = CMP_find_request(tdbb, irq_c_exp_index, IRQ_REQUESTS);
|
||||
/*
|
||||
if (request)
|
||||
{
|
||||
EXE_unwind(tdbb, request);
|
||||
}
|
||||
if (request)
|
||||
{
|
||||
EXE_unwind(tdbb, request);
|
||||
}
|
||||
*/
|
||||
FOR(REQUEST_HANDLE request)
|
||||
IDX IN RDB$INDICES CROSS
|
||||
REL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH
|
||||
IDX.RDB$EXPRESSION_BLR NOT MISSING AND
|
||||
IDX.RDB$INDEX_NAME EQ work->dfw_name.c_str()
|
||||
|
||||
if (!REQUEST(irq_c_exp_index))
|
||||
{
|
||||
REQUEST(irq_c_exp_index) = request;
|
||||
}
|
||||
|
||||
if (!relation)
|
||||
{
|
||||
relation = MET_relation(tdbb, REL.RDB$RELATION_ID);
|
||||
if (relation->rel_name.length() == 0)
|
||||
{
|
||||
relation->rel_name = REL.RDB$RELATION_NAME;
|
||||
}
|
||||
if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0)
|
||||
{
|
||||
SelectivityList selectivity(*tdbb->getDefaultPool());
|
||||
const USHORT id = IDX.RDB$INDEX_ID - 1;
|
||||
IDX_statistics(tdbb, relation, id, selectivity);
|
||||
DFW_update_index(work->dfw_name.c_str(), id, selectivity);
|
||||
|
||||
EXE_unwind(tdbb, request);
|
||||
return false;
|
||||
}
|
||||
if (IDX.RDB$INDEX_ID)
|
||||
{
|
||||
IDX_delete_index(tdbb, relation, IDX.RDB$INDEX_ID - 1);
|
||||
MET_delete_dependencies(tdbb, work->dfw_name,
|
||||
obj_expression_index);
|
||||
MODIFY IDX
|
||||
IDX.RDB$INDEX_ID.NULL = TRUE;
|
||||
END_MODIFY;
|
||||
}
|
||||
if (IDX.RDB$INDEX_INACTIVE)
|
||||
{
|
||||
EXE_unwind(tdbb, request);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IDX.RDB$SEGMENT_COUNT)
|
||||
ERR_post(isc_no_meta_update,
|
||||
isc_arg_gds, isc_no_segments_err,
|
||||
isc_arg_string, ERR_cstring(work->dfw_name), isc_arg_end);
|
||||
/* Msg359: segments not allowed in expression index %s */
|
||||
if (IDX.RDB$UNIQUE_FLAG)
|
||||
idx.idx_flags |= idx_unique;
|
||||
if (IDX.RDB$INDEX_TYPE == 1)
|
||||
idx.idx_flags |= idx_descending;
|
||||
|
||||
CompilerScratch* csb = 0;
|
||||
/* allocate a new pool to contain the expression tree
|
||||
for the expression index */
|
||||
new_pool = JrdMemoryPool::createPool();
|
||||
{
|
||||
Jrd::ContextPoolHolder context(tdbb, new_pool);
|
||||
MET_scan_relation(tdbb, relation);
|
||||
|
||||
if (!IDX.RDB$EXPRESSION_BLR.NULL)
|
||||
{
|
||||
MetaTmp(IDX.RDB$INDEX_NAME)
|
||||
idx.idx_expression = MET_get_dependencies(tdbb, relation,
|
||||
NULL, NULL,
|
||||
&IDX.RDB$EXPRESSION_BLR,
|
||||
&idx.idx_expression_request,
|
||||
&csb, tmp,
|
||||
obj_expression_index, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* fake a description of the index */
|
||||
|
||||
idx.idx_count = 1;
|
||||
idx.idx_flags |= idx_expressn;
|
||||
CMP_get_desc(tdbb, csb, idx.idx_expression,
|
||||
&idx.idx_expression_desc);
|
||||
idx.idx_rpt[0].idx_itype =
|
||||
DFW_assign_index_type(work,
|
||||
idx.idx_expression_desc.dsc_dtype,
|
||||
idx.idx_expression_desc.dsc_sub_type);
|
||||
idx.idx_rpt[0].idx_selectivity = 0;
|
||||
|
||||
delete csb;
|
||||
}
|
||||
|
||||
END_FOR;
|
||||
FOR(REQUEST_HANDLE request)
|
||||
IDX IN RDB$INDICES CROSS
|
||||
REL IN RDB$RELATIONS OVER RDB$RELATION_NAME WITH
|
||||
IDX.RDB$EXPRESSION_BLR NOT MISSING AND
|
||||
IDX.RDB$INDEX_NAME EQ name.c_str()
|
||||
|
||||
if (!REQUEST(irq_c_exp_index))
|
||||
{
|
||||
@ -195,67 +99,146 @@ bool PCMET_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
}
|
||||
|
||||
if (!relation)
|
||||
ERR_post(isc_no_meta_update,
|
||||
isc_arg_gds, isc_idx_create_err,
|
||||
isc_arg_string, ERR_cstring(work->dfw_name), isc_arg_end);
|
||||
// Msg308: can't create index %s
|
||||
|
||||
// Actually create the index
|
||||
|
||||
bool releaseRelationLock = false;
|
||||
Lock* relationLock = DFW_protect_relation(tdbb, transaction, relation,
|
||||
releaseRelationLock);
|
||||
|
||||
SelectivityList selectivity(*tdbb->getDefaultPool());
|
||||
|
||||
current_request = tdbb->getRequest();
|
||||
current_transaction = tdbb->getTransaction();
|
||||
TRA_attach_request(transaction, idx.idx_expression_request);
|
||||
tdbb->setRequest(idx.idx_expression_request);
|
||||
|
||||
try {
|
||||
fb_assert(work->dfw_id <= dbb->dbb_max_idx);
|
||||
idx.idx_id = work->dfw_id;
|
||||
IDX_create_index(tdbb, relation, &idx, work->dfw_name.c_str(), &work->dfw_id,
|
||||
transaction, selectivity);
|
||||
fb_assert(work->dfw_id == idx.idx_id);
|
||||
|
||||
TRA_detach_request(idx.idx_expression_request);
|
||||
tdbb->setRequest(current_request);
|
||||
tdbb->setTransaction(current_transaction);
|
||||
|
||||
DFW_update_index(work->dfw_name.c_str(), idx.idx_id, selectivity);
|
||||
|
||||
// Get rid of the pool containing the expression tree
|
||||
|
||||
if (new_pool) {
|
||||
JrdMemoryPool::deletePool(new_pool);
|
||||
}
|
||||
|
||||
if (relationLock && releaseRelationLock) {
|
||||
DFW_release_protect_lock(tdbb, transaction, relationLock);
|
||||
}
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
TRA_detach_request(idx.idx_expression_request);
|
||||
tdbb->setRequest(current_request);
|
||||
tdbb->setTransaction(current_transaction);
|
||||
|
||||
if (new_pool) {
|
||||
JrdMemoryPool::deletePool(new_pool);
|
||||
relation = MET_relation(tdbb, REL.RDB$RELATION_ID);
|
||||
if (relation->rel_name.length() == 0)
|
||||
{
|
||||
relation->rel_name = REL.RDB$RELATION_NAME;
|
||||
}
|
||||
|
||||
if (relationLock && releaseRelationLock) {
|
||||
DFW_release_protect_lock(tdbb, transaction, relationLock);
|
||||
if (IDX.RDB$INDEX_ID && IDX.RDB$STATISTICS < 0.0)
|
||||
{
|
||||
SelectivityList selectivity(*tdbb->getDefaultPool());
|
||||
const USHORT id = IDX.RDB$INDEX_ID - 1;
|
||||
IDX_statistics(tdbb, relation, id, selectivity);
|
||||
DFW_update_index(name.c_str(), id, selectivity);
|
||||
|
||||
EXE_unwind(tdbb, request);
|
||||
return;
|
||||
}
|
||||
if (IDX.RDB$INDEX_ID)
|
||||
{
|
||||
IDX_delete_index(tdbb, relation, IDX.RDB$INDEX_ID - 1);
|
||||
MET_delete_dependencies(tdbb, name, obj_expression_index);
|
||||
MODIFY IDX
|
||||
IDX.RDB$INDEX_ID.NULL = TRUE;
|
||||
END_MODIFY;
|
||||
}
|
||||
if (IDX.RDB$INDEX_INACTIVE)
|
||||
{
|
||||
EXE_unwind(tdbb, request);
|
||||
return;
|
||||
}
|
||||
|
||||
throw;
|
||||
if (IDX.RDB$SEGMENT_COUNT)
|
||||
ERR_post(isc_no_meta_update,
|
||||
isc_arg_gds, isc_no_segments_err,
|
||||
isc_arg_string, ERR_cstring(name), isc_arg_end);
|
||||
/* Msg359: segments not allowed in expression index %s */
|
||||
if (IDX.RDB$UNIQUE_FLAG)
|
||||
idx.idx_flags |= idx_unique;
|
||||
if (IDX.RDB$INDEX_TYPE == 1)
|
||||
idx.idx_flags |= idx_descending;
|
||||
|
||||
CompilerScratch* csb = 0;
|
||||
/* allocate a new pool to contain the expression tree
|
||||
for the expression index */
|
||||
new_pool = JrdMemoryPool::createPool();
|
||||
{
|
||||
Jrd::ContextPoolHolder context(tdbb, new_pool);
|
||||
MET_scan_relation(tdbb, relation);
|
||||
|
||||
if (!IDX.RDB$EXPRESSION_BLR.NULL)
|
||||
{
|
||||
MetaTmp(IDX.RDB$INDEX_NAME)
|
||||
idx.idx_expression = MET_get_dependencies(tdbb, relation,
|
||||
NULL, NULL,
|
||||
&IDX.RDB$EXPRESSION_BLR,
|
||||
&idx.idx_expression_request,
|
||||
&csb, tmp,
|
||||
obj_expression_index, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* fake a description of the index */
|
||||
|
||||
idx.idx_count = 1;
|
||||
idx.idx_flags |= idx_expressn;
|
||||
CMP_get_desc(tdbb, csb, idx.idx_expression,
|
||||
&idx.idx_expression_desc);
|
||||
idx.idx_rpt[0].idx_itype =
|
||||
DFW_assign_index_type(name,
|
||||
idx.idx_expression_desc.dsc_dtype,
|
||||
idx.idx_expression_desc.dsc_sub_type);
|
||||
idx.idx_rpt[0].idx_selectivity = 0;
|
||||
|
||||
delete csb;
|
||||
}
|
||||
break;
|
||||
|
||||
END_FOR;
|
||||
|
||||
if (!REQUEST(irq_c_exp_index))
|
||||
{
|
||||
REQUEST(irq_c_exp_index) = request;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!relation)
|
||||
ERR_post(isc_no_meta_update,
|
||||
isc_arg_gds, isc_idx_create_err,
|
||||
isc_arg_string, ERR_cstring(name), isc_arg_end);
|
||||
// Msg308: can't create index %s
|
||||
|
||||
// Actually create the index
|
||||
|
||||
bool releaseRelationLock = false;
|
||||
Lock* relationLock = DFW_protect_relation(tdbb, transaction, relation,
|
||||
releaseRelationLock);
|
||||
|
||||
SelectivityList selectivity(*tdbb->getDefaultPool());
|
||||
|
||||
current_request = tdbb->getRequest();
|
||||
current_transaction = tdbb->getTransaction();
|
||||
TRA_attach_request(transaction, idx.idx_expression_request);
|
||||
tdbb->setRequest(idx.idx_expression_request);
|
||||
|
||||
try {
|
||||
fb_assert(id <= dbb->dbb_max_idx);
|
||||
idx.idx_id = id;
|
||||
IDX_create_index(tdbb, relation, &idx, name.c_str(), &id,
|
||||
transaction, selectivity);
|
||||
fb_assert(id == idx.idx_id);
|
||||
|
||||
TRA_detach_request(idx.idx_expression_request);
|
||||
tdbb->setRequest(current_request);
|
||||
tdbb->setTransaction(current_transaction);
|
||||
|
||||
DFW_update_index(name.c_str(), idx.idx_id, selectivity);
|
||||
|
||||
// Get rid of the pool containing the expression tree
|
||||
|
||||
if (new_pool) {
|
||||
JrdMemoryPool::deletePool(new_pool);
|
||||
}
|
||||
|
||||
if (relationLock && releaseRelationLock) {
|
||||
DFW_release_protect_lock(tdbb, transaction, relationLock);
|
||||
}
|
||||
}
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
TRA_detach_request(idx.idx_expression_request);
|
||||
tdbb->setRequest(current_request);
|
||||
tdbb->setTransaction(current_transaction);
|
||||
|
||||
if (new_pool) {
|
||||
JrdMemoryPool::deletePool(new_pool);
|
||||
}
|
||||
|
||||
if (relationLock && releaseRelationLock) {
|
||||
DFW_release_protect_lock(tdbb, transaction, relationLock);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
#ifndef JRD_PCMET_PROTO_H
|
||||
#define JRD_PCMET_PROTO_H
|
||||
|
||||
#include "../common/classes/fb_string.h"
|
||||
|
||||
namespace Jrd {
|
||||
class DeferredWork;
|
||||
class jrd_tra;
|
||||
@ -31,7 +33,7 @@ namespace Jrd {
|
||||
struct index_desc;
|
||||
}
|
||||
|
||||
bool PCMET_expression_index(Jrd::thread_db*, SSHORT, Jrd::DeferredWork*, Jrd::jrd_tra*);
|
||||
void PCMET_expression_index(Jrd::thread_db*, const Firebird::string&, USHORT, Jrd::jrd_tra*);
|
||||
void PCMET_lookup_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*);
|
||||
|
||||
#endif // JRD_PCMET_PROTO_H
|
||||
|
@ -414,7 +414,7 @@ void TRA_commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_flag
|
||||
|
||||
if (retaining_flag
|
||||
&& !(transaction->tra_flags & TRA_write
|
||||
|| transaction->tra_deferred_work))
|
||||
|| transaction->tra_deferred_job))
|
||||
{
|
||||
transaction->tra_flags &= ~TRA_prepared;
|
||||
// Get rid of all user savepoints
|
||||
|
@ -55,6 +55,7 @@ class Record;
|
||||
class VerbAction;
|
||||
class ArrayField;
|
||||
class Attachment;
|
||||
class DeferredJob;
|
||||
|
||||
const SLONG MAX_TRA_NUMBER = MAX_SLONG;
|
||||
|
||||
@ -98,6 +99,7 @@ public:
|
||||
jrd_tra(JrdMemoryPool* p) :
|
||||
tra_pool(p),
|
||||
tra_blobs(p),
|
||||
tra_deferred_job(NULL),
|
||||
tra_resources(*p),
|
||||
tra_context_vars(*p),
|
||||
tra_lock_timeout(DEFAULT_LOCK_TIMEOUT),
|
||||
@ -128,7 +130,7 @@ public:
|
||||
Savepoint* tra_save_free; /* free savepoints */
|
||||
SLONG tra_save_point_number; /* next save point number to use */
|
||||
ULONG tra_flags;
|
||||
class DeferredWork* tra_deferred_work; /* work deferred to commit time */
|
||||
DeferredJob* tra_deferred_job; /* work deferred to commit time */
|
||||
ResourceList tra_resources; /* resource existence list */
|
||||
Firebird::StringMap tra_context_vars; // Context variables for the transaction
|
||||
traRpbList* tra_rpblist; /* active record_param's of given transaction */
|
||||
@ -304,21 +306,6 @@ enum dfw_t {
|
||||
dfw_arg_trg_type // trigger type
|
||||
};
|
||||
|
||||
class DeferredWork : public pool_alloc<type_dfw>
|
||||
{
|
||||
public:
|
||||
enum dfw_t dfw_type; /* type of work deferred */
|
||||
DeferredWork* dfw_next; /* next block in transaction */
|
||||
Lock* dfw_lock; /* relation creation lock */
|
||||
DeferredWork* dfw_args; /* arguments */
|
||||
SLONG dfw_sav_number; /* save point number */
|
||||
USHORT dfw_id; /* object id, if appropriate */
|
||||
USHORT dfw_count; /* count of block posts */
|
||||
Firebird::string dfw_name; /* name of object */
|
||||
public:
|
||||
explicit DeferredWork(MemoryPool& p) : dfw_name(p) { }
|
||||
};
|
||||
|
||||
/* Verb actions */
|
||||
|
||||
class UndoItem {
|
||||
|
@ -1285,8 +1285,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
|
||||
// add index id and name (the latter is required
|
||||
// to delete dependencies correctly)
|
||||
DeferredWork* arg = DFW_post_work_arg(transaction, work, &idx_name, id);
|
||||
arg->dfw_type = dfw_arg_index_name;
|
||||
DFW_post_work_arg(transaction, work, &idx_name, id, dfw_arg_index_name);
|
||||
|
||||
// get partner relation for FK index
|
||||
if (EVL_field(0, rpb->rpb_record, f_idx_foreign, &desc2))
|
||||
@ -1304,16 +1303,14 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
(MET_lookup_partner(tdbb, r2, &idx, index_name)) &&
|
||||
(partner = MET_lookup_relation_id(tdbb, idx.idx_primary_relation, false)) )
|
||||
{
|
||||
DeferredWork* arg2 =
|
||||
DFW_post_work_arg(transaction, work, 0, partner->rel_id);
|
||||
arg2->dfw_type = dfw_arg_partner_rel_id;
|
||||
DFW_post_work_arg(transaction, work, 0, partner->rel_id,
|
||||
dfw_arg_partner_rel_id);
|
||||
}
|
||||
else
|
||||
{ // can't find partner relation - impossible ?
|
||||
// add empty argument to let DFW know dropping
|
||||
// index was bound with FK
|
||||
DeferredWork* arg2 = DFW_post_work_arg(transaction, work, 0, 0);
|
||||
arg2->dfw_type = dfw_arg_partner_rel_id;
|
||||
DFW_post_work_arg(transaction, work, 0, 0, dfw_arg_partner_rel_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1345,9 +1342,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
procedure->prc_id);
|
||||
|
||||
// procedure name to track parameter dependencies
|
||||
DeferredWork* arg = DFW_post_work_arg(transaction, work, &desc,
|
||||
procedure->prc_id);
|
||||
arg->dfw_type = dfw_arg_proc_name;
|
||||
DFW_post_work_arg(transaction, work, &desc, procedure->prc_id, dfw_arg_proc_name);
|
||||
}
|
||||
EVL_field(0, rpb->rpb_record, f_prm_sname, &desc2);
|
||||
DFW_post_work(transaction, dfw_delete_global, &desc2, 0);
|
||||
@ -1403,12 +1398,12 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
work = DFW_post_work(transaction, dfw_delete_trigger, &desc, 0);
|
||||
|
||||
if (!(desc2.dsc_flags & DSC_null))
|
||||
DFW_post_work_arg(transaction, work, &desc2, 0)->dfw_type = dfw_arg_rel_name;
|
||||
DFW_post_work_arg(transaction, work, &desc2, 0, dfw_arg_rel_name);
|
||||
|
||||
if (EVL_field(0, rpb->rpb_record, f_trg_type, &desc2))
|
||||
{
|
||||
DFW_post_work_arg(transaction, work, &desc2,
|
||||
MOV_get_long(&desc2, 0))->dfw_type = dfw_arg_trg_type;
|
||||
MOV_get_long(&desc2, 0), dfw_arg_trg_type);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -2282,11 +2277,9 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb,
|
||||
bool rc1 = EVL_field(0, org_rpb->rpb_record, f_fld_computed, &desc3);
|
||||
bool rc2 = EVL_field(0, new_rpb->rpb_record, f_fld_computed, &desc4);
|
||||
if (rc1 != rc2 || rc1 && MOV_compare(&desc3, &desc4)) {
|
||||
dw = DFW_post_work_arg(transaction, dw, &desc1, 0);
|
||||
dw->dfw_type = dfw_arg_force_computed;
|
||||
DFW_post_work_arg(transaction, dw, &desc1, 0, dfw_arg_force_computed);
|
||||
}
|
||||
}
|
||||
|
||||
DFW_post_work(transaction, dfw_modify_field, &desc1, 0);
|
||||
}
|
||||
break;
|
||||
@ -2327,12 +2320,12 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb,
|
||||
DeferredWork* dw = DFW_post_work(transaction, dfw_modify_trigger, &desc1, 0);
|
||||
|
||||
if (EVL_field(0, new_rpb->rpb_record, f_trg_rname, &desc2))
|
||||
DFW_post_work_arg(transaction, dw, &desc2, 0)->dfw_type = dfw_arg_rel_name;
|
||||
DFW_post_work_arg(transaction, dw, &desc2, 0, dfw_arg_rel_name);
|
||||
|
||||
if (EVL_field(0, new_rpb->rpb_record, f_trg_type, &desc2))
|
||||
{
|
||||
DFW_post_work_arg(transaction, dw, &desc2,
|
||||
MOV_get_long(&desc2, 0))->dfw_type = dfw_arg_trg_type;
|
||||
MOV_get_long(&desc2, 0), dfw_arg_trg_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -2688,7 +2681,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
}
|
||||
|
||||
if (check_blr)
|
||||
DFW_post_work_arg(transaction, work, NULL, 0)->dfw_type = dfw_arg_check_blr;
|
||||
DFW_post_work_arg(transaction, work, NULL, 0, dfw_arg_check_blr);
|
||||
} // scope
|
||||
set_system_flag(tdbb, rpb, f_prc_sys_flag, 0);
|
||||
break;
|
||||
@ -2773,12 +2766,12 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
work = DFW_post_work(transaction, dfw_create_trigger, &desc, 0);
|
||||
|
||||
if (!(desc2.dsc_flags & DSC_null))
|
||||
DFW_post_work_arg(transaction, work, &desc2, 0)->dfw_type = dfw_arg_rel_name;
|
||||
DFW_post_work_arg(transaction, work, &desc2, 0, dfw_arg_rel_name);
|
||||
|
||||
if (EVL_field(0, rpb->rpb_record, f_trg_type, &desc2))
|
||||
{
|
||||
DFW_post_work_arg(transaction, work, &desc2,
|
||||
MOV_get_long(&desc2, 0))->dfw_type = dfw_arg_trg_type;
|
||||
MOV_get_long(&desc2, 0), dfw_arg_trg_type);
|
||||
}
|
||||
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user