8
0
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:
alexpeshkoff 2009-09-18 12:23:32 +00:00
parent 29819be1fa
commit 57b400137d
11 changed files with 989 additions and 526 deletions

305
src/common/classes/Hash.h Normal file
View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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