"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/jrd/vio.cpp" between
Firebird-3.0.2.32703-0.tar.bz2 and Firebird-3.0.4.33054-0.tar.bz2

About: Firebird is a relational database offering many ANSI SQL standard features.

vio.cpp  (Firebird-3.0.2.32703-0.tar.bz2):vio.cpp  (Firebird-3.0.4.33054-0.tar.bz2)
skipping to change at line 115 skipping to change at line 115
static void expunge(thread_db*, record_param*, const jrd_tra*, ULONG); static void expunge(thread_db*, record_param*, const jrd_tra*, ULONG);
static bool dfw_should_know(record_param* org_rpb, record_param* new_rpb, static bool dfw_should_know(record_param* org_rpb, record_param* new_rpb,
USHORT irrelevant_field, bool void_update_is_relevant = false); USHORT irrelevant_field, bool void_update_is_relevant = false);
static void garbage_collect(thread_db*, record_param*, ULONG, RecordStack&); static void garbage_collect(thread_db*, record_param*, ULONG, RecordStack&);
static void garbage_collect_idx(thread_db*, record_param*, Record*, Record*); static void garbage_collect_idx(thread_db*, record_param*, Record*, Record*);
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
int vio_debug_flag = 0; int vio_debug_flag = DEBUG_TRACE_ALL_INFO;
void VIO_trace(int level, const char* format, ...) void VIO_trace(int level, const char* format, ...)
{ {
if (vio_debug_flag <= level) if (vio_debug_flag <= level)
return; return;
Firebird::string buffer; Firebird::string buffer;
va_list params; va_list params;
va_start(params, format); va_start(params, format);
buffer.vprintf(format, params); buffer.vprintf(format, params);
skipping to change at line 168 skipping to change at line 168
record_param*, record_param*, PageStack&, bool); record_param*, record_param*, PageStack&, bool);
static void protect_system_table_insert(thread_db* tdbb, const jrd_req* req, con st jrd_rel* relation, static void protect_system_table_insert(thread_db* tdbb, const jrd_req* req, con st jrd_rel* relation,
bool force_flag = false); bool force_flag = false);
static void protect_system_table_delupd(thread_db* tdbb, const jrd_rel* relation , const char* operation, static void protect_system_table_delupd(thread_db* tdbb, const jrd_rel* relation , const char* operation,
bool force_flag = false); bool force_flag = false);
static void purge(thread_db*, record_param*); static void purge(thread_db*, record_param*);
static void replace_record(thread_db*, record_param*, PageStack*, const jrd_tra* ); static void replace_record(thread_db*, record_param*, PageStack*, const jrd_tra* );
static void refresh_fk_fields(thread_db*, Record*, record_param*, record_param*) ; static void refresh_fk_fields(thread_db*, Record*, record_param*, record_param*) ;
static SSHORT set_metadata_id(thread_db*, Record*, USHORT, drq_type_t, const cha r*); static SSHORT set_metadata_id(thread_db*, Record*, USHORT, drq_type_t, const cha r*);
static void set_nbackup_id(thread_db*, Record*, USHORT, drq_type_t, const char*) ;
static void set_owner_name(thread_db*, Record*, USHORT); static void set_owner_name(thread_db*, Record*, USHORT);
static bool set_security_class(thread_db*, Record*, USHORT); static bool set_security_class(thread_db*, Record*, USHORT);
static void set_system_flag(thread_db*, Record*, USHORT); static void set_system_flag(thread_db*, Record*, USHORT);
static void update_in_place(thread_db*, jrd_tra*, record_param*, record_param*); static void update_in_place(thread_db*, jrd_tra*, record_param*, record_param*);
static void verb_post(thread_db*, jrd_tra*, record_param*, Record*, const bool, const bool); static void verb_post(thread_db*, jrd_tra*, record_param*, Record*, const bool, const bool);
static bool assert_gc_enabled(const jrd_tra* transaction, const jrd_rel* relatio n) static bool assert_gc_enabled(const jrd_tra* transaction, const jrd_rel* relatio n)
{ {
/************************************** /**************************************
* *
skipping to change at line 426 skipping to change at line 427
* But this record is doomed, and if we don't get it somebody * But this record is doomed, and if we don't get it somebody
* will. * will.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase(); Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb); CHECK_DBB(dbb);
fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation)); fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation));
jrd_rel* const relation = rpb->rpb_relation;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES, VIO_trace(DEBUG_WRITES,
"VIO_backout (record_param %" QUADFORMAT"d, transaction %" SQUADF "VIO_backout (rel_id %u, record_param %" SQUADFORMAT", transactio
ORMAT")\n", n %" SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans
: 0); action->tra_number : 0);
#endif #endif
jrd_rel* const relation = rpb->rpb_relation;
// If there is data in the record, fetch it now. If the old version // If there is data in the record, fetch it now. If the old version
// is a differences record, we will need it sooner. In any case, we // is a differences record, we will need it sooner. In any case, we
// will need it eventually to clean up blobs and indices. If the record // will need it eventually to clean up blobs and indices. If the record
// has changed in between, stop now before things get worse. // has changed in between, stop now before things get worse.
record_param temp = *rpb; record_param temp = *rpb;
if (!DPM_get(tdbb, &temp, LCK_read)) if (!DPM_get(tdbb, &temp, LCK_read))
return; return;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
skipping to change at line 552 skipping to change at line 553
} }
} }
// Re-fetch the record. // Re-fetch the record.
if (!DPM_get(tdbb, rpb, LCK_write)) if (!DPM_get(tdbb, rpb, LCK_write))
return; return;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
if (temp2.rpb_b_page != rpb->rpb_b_page || temp.rpb_b_line != rpb->rpb_b_ line || if (temp2.rpb_b_page != rpb->rpb_b_page || temp.rpb_b_line != rpb->rpb_b_ line ||
temp.rpb_transaction_nr != rpb->rpb_transaction_nr) temp.rpb_transaction_nr != rpb->rpb_transaction_nr)
{ {
VIO_trace(DEBUG_WRITES_INFO, VIO_trace(DEBUG_WRITES_INFO,
" record changed!)\n"); " record changed!)\n");
} }
#endif #endif
// If the record is in any way suspicious, release the record and give up . // If the record is in any way suspicious, release the record and give up .
if (rpb->rpb_b_page != temp2.rpb_b_page || rpb->rpb_b_line != temp2.rpb_b _line || if (rpb->rpb_b_page != temp2.rpb_b_page || rpb->rpb_b_line != temp2.rpb_b _line ||
rpb->rpb_transaction_nr != temp2.rpb_transaction_nr) rpb->rpb_transaction_nr != temp2.rpb_transaction_nr)
skipping to change at line 612 skipping to change at line 613
fb_assert(rpb->rpb_flags & rpb_gc_active); fb_assert(rpb->rpb_flags & rpb_gc_active);
rpb->rpb_flags &= ~rpb_gc_active; rpb->rpb_flags &= ~rpb_gc_active;
temp2 = *rpb; temp2 = *rpb;
rpb->rpb_undo = old_data; rpb->rpb_undo = old_data;
if (rpb->rpb_flags & rpb_delta) if (rpb->rpb_flags & rpb_delta)
rpb->rpb_prior = data; rpb->rpb_prior = data;
} }
gcLockGuard.release();
delete_record(tdbb, rpb, 0, NULL); delete_record(tdbb, rpb, 0, NULL);
tdbb->bumpRelStats(RuntimeStatistics::RECORD_BACKOUTS, relation-> rel_id); tdbb->bumpRelStats(RuntimeStatistics::RECORD_BACKOUTS, relation-> rel_id);
return; return;
} }
// If both record versions are on the same page, things are a little simp ler // If both record versions are on the same page, things are a little simp ler
samePage = (rpb->rpb_page == temp.rpb_page && !rpb->rpb_prior); samePage = (rpb->rpb_page == temp.rpb_page && !rpb->rpb_prior);
deleted = (temp2.rpb_flags & rpb_deleted); deleted = (temp2.rpb_flags & rpb_deleted);
skipping to change at line 738 skipping to change at line 739
Jrd::Attachment* const attachment = transaction->tra_attachment; Jrd::Attachment* const attachment = transaction->tra_attachment;
jrd_rel* const relation = rpb->rpb_relation; jrd_rel* const relation = rpb->rpb_relation;
const bool gcPolicyCooperative = dbb->dbb_flags & DBB_gc_cooperative; const bool gcPolicyCooperative = dbb->dbb_flags & DBB_gc_cooperative;
const bool gcPolicyBackground = dbb->dbb_flags & DBB_gc_background; const bool gcPolicyBackground = dbb->dbb_flags & DBB_gc_background;
const TraNumber oldest_snapshot = relation->isTemporary() ? const TraNumber oldest_snapshot = relation->isTemporary() ?
attachment->att_oldest_snapshot : transaction->tra_oldest_active; attachment->att_oldest_snapshot : transaction->tra_oldest_active;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL, VIO_trace(DEBUG_TRACE_ALL,
"VIO_chase_record_version (record_param %" QUADFORMAT"d, transact ion %" "VIO_chase_record_version (rel_id %u, record_param %" QUADFORMAT" d, transaction %"
SQUADFORMAT", pool %p)\n", SQUADFORMAT", pool %p)\n",
relation->rel_id,
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0, rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0,
(void*) pool); (void*) pool);
VIO_trace(DEBUG_TRACE_ALL_INFO, VIO_trace(DEBUG_TRACE_ALL_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
skipping to change at line 763 skipping to change at line 765
// Reset (if appropriate) the garbage collect active flag to reattempt th e backout // Reset (if appropriate) the garbage collect active flag to reattempt th e backout
if (rpb->rpb_flags & rpb_gc_active) if (rpb->rpb_flags & rpb_gc_active)
checkGCActive(tdbb, rpb, state); checkGCActive(tdbb, rpb, state);
// Take care about modifications performed by our own transaction // Take care about modifications performed by our own transaction
rpb->rpb_runtime_flags &= ~RPB_UNDO_FLAGS; rpb->rpb_runtime_flags &= ~RPB_UNDO_FLAGS;
int forceBack = 0; int forceBack = 0;
if (rpb->rpb_stream_flags & RPB_s_unstable)
noundo = true;
if (state == tra_us && !noundo && !(transaction->tra_flags & TRA_system)) if (state == tra_us && !noundo && !(transaction->tra_flags & TRA_system))
{ {
switch (get_undo_data(tdbb, transaction, rpb, pool)) switch (get_undo_data(tdbb, transaction, rpb, pool))
{ {
case udExists: case udExists:
return true; return true;
case udForceBack: case udForceBack:
forceBack = 1; forceBack = 1;
break; break;
case udForceTwice: case udForceTwice:
skipping to change at line 1281 skipping to change at line 1286
{ {
DSC org_desc, new_desc; DSC org_desc, new_desc;
for (USHORT i = 0; i < new_record->getFormat()->fmt_count; i++) for (USHORT i = 0; i < new_record->getFormat()->fmt_count; i++)
{ {
new_record->clearNull(i); new_record->clearNull(i);
if (EVL_field(new_rpb->rpb_relation, new_record, i, &new_ desc)) if (EVL_field(new_rpb->rpb_relation, new_record, i, &new_ desc))
{ {
if (EVL_field(org_rpb->rpb_relation, org_record, i, &org_desc)) if (EVL_field(org_rpb->rpb_relation, org_record, i, &org_desc))
MOV_move(tdbb, &org_desc, &new_desc); {
if (DTYPE_IS_BLOB_OR_QUAD(org_desc.dsc_dt
ype) || DTYPE_IS_BLOB_OR_QUAD(new_desc.dsc_dtype))
Jrd::blb::move(tdbb, &org_desc, &
new_desc, new_rpb, i);
else
MOV_move(tdbb, &org_desc, &new_de
sc);
}
else else
{ {
new_record->setNull(i); new_record->setNull(i);
if (new_desc.dsc_dtype) if (new_desc.dsc_dtype)
memset(new_desc.dsc_address, 0, n ew_desc.dsc_length); memset(new_desc.dsc_address, 0, n ew_desc.dsc_length);
} }
} }
} }
} }
skipping to change at line 1312 skipping to change at line 1322
* Functional description * Functional description
* Given an active record parameter block, fetch the full record. * Given an active record parameter block, fetch the full record.
* *
* This routine is called with an active record_param and exits with * This routine is called with an active record_param and exits with
* an INactive record_param. Yes, Virginia, getting the data for a * an INactive record_param. Yes, Virginia, getting the data for a
* record means losing control of the record. This turns out * record means losing control of the record. This turns out
* to matter a lot. * to matter a lot.
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
jrd_rel* const relation = rpb->rpb_relation;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_READS, VIO_trace(DEBUG_READS,
"VIO_data (record_param %" QUADFORMAT"d, pool %p)\n", "VIO_data (rel_id %u, record_param %" QUADFORMAT"d, pool %p)\n",
rpb->rpb_number.getValue(), (void*) pool); relation->rel_id, rpb->rpb_number.getValue(), (void*)pool);
VIO_trace(DEBUG_READS_INFO, VIO_trace(DEBUG_READS_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_page, rpb->rpb_line,
rpb->rpb_transaction_nr, rpb->rpb_flags, rpb->rpb_transaction_nr, rpb->rpb_flags,
rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
// If we're not already set up for this format version number, find // If we're not already set up for this format version number, find
// the format block and set up the record block. This is a performance // the format block and set up the record block. This is a performance
// optimization. // optimization.
jrd_rel* const relation = rpb->rpb_relation;
Record* const record = VIO_record(tdbb, rpb, NULL, pool); Record* const record = VIO_record(tdbb, rpb, NULL, pool);
const Format* const format = record->getFormat(); const Format* const format = record->getFormat();
// If the record is a delta version, start with data from prior record. // If the record is a delta version, start with data from prior record.
UCHAR* tail; UCHAR* tail;
const UCHAR* tail_end; const UCHAR* tail_end;
UCHAR differences[MAX_DIFFERENCES]; UCHAR differences[MAX_DIFFERENCES];
// Primary record version not uses prior version // Primary record version not uses prior version
Record* prior = (rpb->rpb_flags & rpb_chained) ? rpb->rpb_prior : NULL; Record* prior = (rpb->rpb_flags & rpb_chained) ? rpb->rpb_prior : NULL;
skipping to change at line 1438 skipping to change at line 1449
* *
* This routine is entered with an inactive * This routine is entered with an inactive
* record_param and leaves having created an erased * record_param and leaves having created an erased
* stub. * stub.
* *
**************************************/ **************************************/
MetaName object_name, package_name; MetaName object_name, package_name;
SET_TDBB(tdbb); SET_TDBB(tdbb);
jrd_req* request = tdbb->getRequest(); jrd_req* request = tdbb->getRequest();
jrd_rel* relation = rpb->rpb_relation;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES, VIO_trace(DEBUG_WRITES,
"VIO_erase (record_param %" QUADFORMAT"d, transaction %" SQUADFOR "VIO_erase (rel_id %u, record_param %" QUADFORMAT"d, transaction
MAT")\n", %" SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction->tra_number); relation->rel_id, rpb->rpb_number.getValue(), transaction->tra_nu
mber);
VIO_trace(DEBUG_WRITES_INFO, VIO_trace(DEBUG_WRITES_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
skipping to change at line 1477 skipping to change at line 1489
if (transaction->tra_flags & TRA_system) if (transaction->tra_flags & TRA_system)
{ {
// hvlad: what if record was created\modified by user tx also, // hvlad: what if record was created\modified by user tx also,
// i.e. if there is backversion ??? // i.e. if there is backversion ???
VIO_backout(tdbb, rpb, transaction); VIO_backout(tdbb, rpb, transaction);
return; return;
} }
transaction->tra_flags |= TRA_write; transaction->tra_flags |= TRA_write;
jrd_rel* relation = rpb->rpb_relation;
check_gbak_cheating_delete(tdbb, relation); check_gbak_cheating_delete(tdbb, relation);
// If we're about to erase a system relation, check to make sure // If we're about to erase a system relation, check to make sure
// everything is completely kosher. // everything is completely kosher.
DSC desc, desc2; DSC desc, desc2;
if (needDfw(tdbb, transaction)) if (needDfw(tdbb, transaction))
{ {
skipping to change at line 1638 skipping to change at line 1649
EVL_field(0, rpb->rpb_record, f_fun_id, &desc2); EVL_field(0, rpb->rpb_record, f_fun_id, &desc2);
id = MOV_get_long(&desc2, 0); id = MOV_get_long(&desc2, 0);
DFW_post_work(transaction, dfw_delete_function, &desc, id , package_name); DFW_post_work(transaction, dfw_delete_function, &desc, id , package_name);
Function::lookup(tdbb, id, false, true, 0); Function::lookup(tdbb, id, false, true, 0);
break; break;
case rel_indices: case rel_indices:
protect_system_table_delupd(tdbb, relation, "DELETE"); protect_system_table_delupd(tdbb, relation, "DELETE");
EVL_field(0, rpb->rpb_record, f_idx_relation, &desc); EVL_field(0, rpb->rpb_record, f_idx_relation, &desc);
SCL_check_relation(tdbb, &desc, SCL_control); EVL_field(0, rpb->rpb_record, f_idx_sys_flag, &desc2);
SCL_check_relation(tdbb, &desc, SCL_control, MOV_get_long
(&desc2, 0) == 1);
EVL_field(0, rpb->rpb_record, f_idx_id, &desc2); EVL_field(0, rpb->rpb_record, f_idx_id, &desc2);
if ( (id = MOV_get_long(&desc2, 0)) ) if ( (id = MOV_get_long(&desc2, 0)) )
{ {
MetaName relation_name; MetaName relation_name;
MOV_get_metaname(&desc, relation_name); MOV_get_metaname(&desc, relation_name);
r2 = MET_lookup_relation(tdbb, relation_name); r2 = MET_lookup_relation(tdbb, relation_name);
fb_assert(r2); fb_assert(r2);
DSC idx_name; DSC idx_name;
EVL_field(0, rpb->rpb_record, f_idx_name, &idx_na me); EVL_field(0, rpb->rpb_record, f_idx_name, &idx_na me);
skipping to change at line 1974 skipping to change at line 1986
* record. This is called during index creation to avoid * record. This is called during index creation to avoid
* unnecessary work as well as false duplicate records. * unnecessary work as well as false duplicate records.
* *
* If the record complete goes away, return false. * If the record complete goes away, return false.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
Jrd::Attachment* attachment = transaction->tra_attachment; Jrd::Attachment* attachment = transaction->tra_attachment;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE, VIO_trace(DEBUG_TRACE,
"VIO_garbage_collect (record_param %" QUADFORMAT"d, transaction % " "VIO_garbage_collect (rel_id %u, record_param %" QUADFORMAT"d, tr ansaction %"
SQUADFORMAT")\n", SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0); relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans action->tra_number : 0);
VIO_trace(DEBUG_TRACE_INFO, VIO_trace(DEBUG_TRACE_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
jrd_rel::GCShared gcGuard(tdbb, rpb->rpb_relation); jrd_rel::GCShared gcGuard(tdbb, rpb->rpb_relation);
skipping to change at line 2107 skipping to change at line 2120
* *
************************************** **************************************
* *
* Functional description * Functional description
* Get a specific record from a relation. * Get a specific record from a relation.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS, VIO_trace(DEBUG_READS,
"VIO_get (record_param %" QUADFORMAT"d, transaction %" SQUADFORMA "VIO_get (rel_id %u, record_param %" QUADFORMAT"d, transaction %"
T", pool %p)\n", SQUADFORMAT", pool %p)\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans
: 0, action->tra_number : 0,
(void*) pool); (void*) pool);
#endif #endif
// Fetch data page from a modify/erase input stream with a write // Fetch data page from a modify/erase input stream with a write
// lock. This saves an upward conversion to a write lock when // lock. This saves an upward conversion to a write lock when
// refetching the page in the context of the output stream. // refetching the page in the context of the output stream.
const USHORT lock_type = (rpb->rpb_stream_flags & RPB_s_update) ? LCK_wri te : LCK_read; const USHORT lock_type = (rpb->rpb_stream_flags & RPB_s_update) ? LCK_wri te : LCK_read;
if (!DPM_get(tdbb, rpb, lock_type) || if (!DPM_get(tdbb, rpb, lock_type) ||
skipping to change at line 2185 skipping to change at line 2199
* looking to see if a primary key/unique key exists. For a * looking to see if a primary key/unique key exists. For a
* no wait transaction, if state of transaction inserting primary key * no wait transaction, if state of transaction inserting primary key
* record is tra_active, we should not see the uncommitted record * record is tra_active, we should not see the uncommitted record
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment(); Attachment* const attachment = tdbb->getAttachment();
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE, VIO_trace(DEBUG_TRACE,
"VIO_get_current (record_param %" QUADFORMAT"d, transaction %" SQ "VIO_get_current (rel_id %u, record_param %" QUADFORMAT"d, transa
UADFORMAT", pool %p)\n", ction %" SQUADFORMAT", pool %p)\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans
: 0, action->tra_number : 0,
(void*) pool); (void*) pool);
#endif #endif
rec_tx_active = false; rec_tx_active = false;
bool counted = false; bool counted = false;
while (true) while (true)
{ {
// If the record doesn't exist, no problem. // If the record doesn't exist, no problem.
skipping to change at line 2320 skipping to change at line 2335
if (rpb->rpb_flags & rpb_deleted) if (rpb->rpb_flags & rpb_deleted)
{ {
CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); CCH_RELEASE(tdbb, &rpb->getWindow(tdbb));
return false; return false;
} }
VIO_data(tdbb, rpb, pool); VIO_data(tdbb, rpb, pool);
return true; return true;
case tra_limbo:
if (!(transaction->tra_flags & TRA_ignore_limbo))
ERR_post(Arg::Gds(isc_rec_in_limbo) << Arg::Num(r
pb->rpb_transaction_nr));
// fall thru
case tra_active: case tra_active:
// clear lock error from status vector // clear lock error from status vector
fb_utils::init_status(tdbb->tdbb_status_vector); fb_utils::init_status(tdbb->tdbb_status_vector);
rec_tx_active = true; rec_tx_active = true;
// 1. if record just inserted // 1. if record just inserted
// then FK can't reference it but PK must check it 's new value // then FK can't reference it but PK must check it 's new value
// 2. if record just deleted // 2. if record just deleted
// then FK can't reference it but PK must check it's o ld value // then FK can't reference it but PK must check it's o ld value
// 3. if record just modified // 3. if record just modified
skipping to change at line 2364 skipping to change at line 2384
{ {
jrd_rel::GCShared gcGuard(tdbb, rpb->rpb_relation ); jrd_rel::GCShared gcGuard(tdbb, rpb->rpb_relation );
if (!gcGuard.gcEnabled()) if (!gcGuard.gcEnabled())
return !foreign_key; return !foreign_key;
VIO_backout(tdbb, rpb, transaction); VIO_backout(tdbb, rpb, transaction);
} }
break; break;
case tra_limbo:
BUGCHECK(184); // limbo impossible
break;
default: default:
fb_assert(false); fb_assert(false);
} }
} }
return !(rpb->rpb_flags & rpb_deleted); return !(rpb->rpb_flags & rpb_deleted);
} }
void VIO_init(thread_db* tdbb) void VIO_init(thread_db* tdbb)
{ {
skipping to change at line 2500 skipping to change at line 2516
* *
************************************** **************************************
* *
* Functional description * Functional description
* Modify an existing record. * Modify an existing record.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
MetaName object_name, package_name; MetaName object_name, package_name;
jrd_rel* relation = org_rpb->rpb_relation;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES, VIO_trace(DEBUG_WRITES,
"VIO_modify (org_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d, " "VIO_modify (rel_id %u, org_rpb %" QUADFORMAT"d, new_rpb %" QUADF ORMAT"d, "
"transaction %" SQUADFORMAT")\n", "transaction %" SQUADFORMAT")\n",
org_rpb->rpb_number.getValue(), new_rpb->rpb_number.getValue(), relation->rel_id, org_rpb->rpb_number.getValue(), new_rpb->rpb_nu mber.getValue(),
transaction ? transaction->tra_number : 0); transaction ? transaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO, VIO_trace(DEBUG_WRITES_INFO,
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr , org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr ,
org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line, org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line,
org_rpb->rpb_f_page, org_rpb->rpb_f_line); org_rpb->rpb_f_page, org_rpb->rpb_f_line);
#endif #endif
jrd_rel* relation = org_rpb->rpb_relation;
transaction->tra_flags |= TRA_write; transaction->tra_flags |= TRA_write;
new_rpb->rpb_transaction_nr = transaction->tra_number; new_rpb->rpb_transaction_nr = transaction->tra_number;
new_rpb->rpb_flags = 0; new_rpb->rpb_flags = 0;
new_rpb->getWindow(tdbb).win_flags = WIN_secondary; new_rpb->getWindow(tdbb).win_flags = WIN_secondary;
// If the stream was sorted, the various fields in the rpb are // If the stream was sorted, the various fields in the rpb are
// probably junk. Just to make sure that everything is cool, // probably junk. Just to make sure that everything is cool,
// refetch and release the record. // refetch and release the record.
if (org_rpb->rpb_runtime_flags & (RPB_refetch | RPB_undo_read)) if (org_rpb->rpb_runtime_flags & (RPB_refetch | RPB_undo_read))
skipping to change at line 2983 skipping to change at line 2999
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
// Fetch data page from a modify/erase input stream with a write // Fetch data page from a modify/erase input stream with a write
// lock. This saves an upward conversion to a write lock when // lock. This saves an upward conversion to a write lock when
// refetching the page in the context of the output stream. // refetching the page in the context of the output stream.
const USHORT lock_type = (rpb->rpb_stream_flags & RPB_s_update) ? LCK_wri te : LCK_read; const USHORT lock_type = (rpb->rpb_stream_flags & RPB_s_update) ? LCK_wri te : LCK_read;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE, VIO_trace(DEBUG_TRACE,
"VIO_next_record (record_param %" QUADFORMAT"d, transaction %" SQ "VIO_next_record (rel_id %u, record_param %" QUADFORMAT"d, transa
UADFORMAT", pool %p)\n", ction %" SQUADFORMAT", pool %p)\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans
: 0, action->tra_number : 0,
(void*) pool); (void*) pool);
VIO_trace(DEBUG_TRACE_INFO, VIO_trace(DEBUG_TRACE_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
skipping to change at line 3049 skipping to change at line 3066
* *
************************************** **************************************
* *
* Functional description * Functional description
* Allocate a record block big enough for a given format. * Allocate a record block big enough for a given format.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE, VIO_trace(DEBUG_TRACE,
"VIO_record (record_param %" QUADFORMAT"d, format %d, pool %p)\n" "VIO_record (rel_id %u, record_param %" QUADFORMAT"d, format %d,
, pool %p)\n",
rpb->rpb_number.getValue(), format ? format->fmt_version : 0, relation->rel_id, rpb->rpb_number.getValue(), format ? format->fm
t_version : 0,
(void*) pool); (void*) pool);
#endif #endif
// If format wasn't given, look one up // If format wasn't given, look one up
if (!format) if (!format)
format = MET_format(tdbb, rpb->rpb_relation, rpb->rpb_format_numb er); format = MET_format(tdbb, rpb->rpb_relation, rpb->rpb_format_numb er);
Record* record = rpb->rpb_record; Record* record = rpb->rpb_record;
skipping to change at line 3090 skipping to change at line 3108
* V I O _ r e f e t c h _ r e c o r d * V I O _ r e f e t c h _ r e c o r d
* *
************************************** **************************************
* *
* Functional description * Functional description
* Refetch & release the record, if we unsure, * Refetch & release the record, if we unsure,
* whether information about it is still valid. * whether information about it is still valid.
* *
**************************************/ **************************************/
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_READS, VIO_trace(DEBUG_READS,
"VIO_refetch_record (record_param %" QUADFORMAT"d, transaction %" "VIO_refetch_record (rel_id %u, record_param %" QUADFORMAT"d, tra
SQUADFORMAT")\n", nsaction %" SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans
: 0); action->tra_number : 0);
#endif #endif
const TraNumber tid_fetch = rpb->rpb_transaction_nr; const TraNumber tid_fetch = rpb->rpb_transaction_nr;
if (!DPM_get(tdbb, rpb, LCK_read) || if (!DPM_get(tdbb, rpb, LCK_read) ||
!VIO_chase_record_version(tdbb, rpb, transaction, tdbb->getDefaul tPool(), writelock, noundo)) !VIO_chase_record_version(tdbb, rpb, transaction, tdbb->getDefaul tPool(), writelock, noundo))
{ {
if (writelock) if (writelock)
return false; return false;
skipping to change at line 3182 skipping to change at line 3201
* V I O _ s t o r e * V I O _ s t o r e
* *
************************************** **************************************
* *
* Functional description * Functional description
* Store a new record. * Store a new record.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
jrd_req* const request = tdbb->getRequest(); jrd_req* const request = tdbb->getRequest();
jrd_rel* relation = rpb->rpb_relation;
DeferredWork* work = NULL; DeferredWork* work = NULL;
MetaName package_name; MetaName package_name;
USHORT object_id; USHORT object_id;
MetaName object_name; MetaName object_name;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES, VIO_trace(DEBUG_WRITES,
"VIO_store (record_param %" QUADFORMAT"d, transaction %" SQUADFOR "VIO_store (rel_id %u, record_param %" QUADFORMAT"d, transaction
MAT %" SQUADFORMAT
")\n", rpb->rpb_number.getValue(), ")\n", relation->rel_id, rpb->rpb_number.getValue(),
transaction ? transaction->tra_number : 0); transaction ? transaction->tra_number : 0);
#endif #endif
transaction->tra_flags |= TRA_write; transaction->tra_flags |= TRA_write;
jrd_rel* relation = rpb->rpb_relation;
DSC desc, desc2; DSC desc, desc2;
check_gbak_cheating_insupd(tdbb, relation, "INSERT"); check_gbak_cheating_insupd(tdbb, relation, "INSERT");
if (needDfw(tdbb, transaction)) if (needDfw(tdbb, transaction))
{ {
switch ((RIDS) relation->rel_id) switch ((RIDS) relation->rel_id)
{ {
case rel_pages: case rel_pages:
case rel_formats: case rel_formats:
skipping to change at line 3338 skipping to change at line 3357
if (package_name.isEmpty()) if (package_name.isEmpty())
{ {
if (set_security_class(tdbb, rpb->rpb_record, f_f un_class)) if (set_security_class(tdbb, rpb->rpb_record, f_f un_class))
DFW_post_work(transaction, dfw_grant, &de sc, obj_udf); DFW_post_work(transaction, dfw_grant, &de sc, obj_udf);
} }
break; break;
case rel_indices: case rel_indices:
protect_system_table_insert(tdbb, request, relation); protect_system_table_insert(tdbb, request, relation);
EVL_field(0, rpb->rpb_record, f_idx_relation, &desc); EVL_field(0, rpb->rpb_record, f_idx_relation, &desc);
SCL_check_relation(tdbb, &desc, SCL_control); EVL_field(0, rpb->rpb_record, f_idx_sys_flag, &desc2);
SCL_check_relation(tdbb, &desc, SCL_control, MOV_get_long
(&desc2, 0) == 1);
EVL_field(0, rpb->rpb_record, f_idx_name, &desc); EVL_field(0, rpb->rpb_record, f_idx_name, &desc);
if (EVL_field(0, rpb->rpb_record, f_idx_exp_blr, &desc2)) if (EVL_field(0, rpb->rpb_record, f_idx_exp_blr, &desc2))
{ {
DFW_post_work(transaction, dfw_create_expression_ index, &desc, DFW_post_work(transaction, dfw_create_expression_ index, &desc,
tdbb->getDatabase()->db b_max_idx); tdbb->getDatabase()->db b_max_idx);
} }
else { else {
DFW_post_work(transaction, dfw_create_index, &des c, tdbb->getDatabase()->dbb_max_idx); DFW_post_work(transaction, dfw_create_index, &des c, tdbb->getDatabase()->dbb_max_idx);
} }
set_system_flag(tdbb, rpb->rpb_record, f_idx_sys_flag); set_system_flag(tdbb, rpb->rpb_record, f_idx_sys_flag);
skipping to change at line 3508 skipping to change at line 3528
f_xcp_number, drq_g_nxt_x cp_id, "RDB$EXCEPTIONS"); f_xcp_number, drq_g_nxt_x cp_id, "RDB$EXCEPTIONS");
set_system_flag(tdbb, rpb->rpb_record, f_xcp_sys_flag); set_system_flag(tdbb, rpb->rpb_record, f_xcp_sys_flag);
set_owner_name(tdbb, rpb->rpb_record, f_xcp_owner); set_owner_name(tdbb, rpb->rpb_record, f_xcp_owner);
if (set_security_class(tdbb, rpb->rpb_record, f_xcp_class )) if (set_security_class(tdbb, rpb->rpb_record, f_xcp_class ))
DFW_post_work(transaction, dfw_grant, &desc, obj_ exception); DFW_post_work(transaction, dfw_grant, &desc, obj_ exception);
break; break;
case rel_backup_history: case rel_backup_history:
if (!tdbb->getAttachment()->locksmith()) if (!tdbb->getAttachment()->locksmith())
protect_system_table_insert(tdbb, request, relati on); protect_system_table_insert(tdbb, request, relati on);
set_metadata_id(tdbb, rpb->rpb_record, set_nbackup_id(tdbb, rpb->rpb_record,
f_backup_id, drq_g_nxt_nb akhist_id, "RDB$BACKUP_HISTORY"); f_backup_id, drq_g_nxt_nb akhist_id, "RDB$BACKUP_HISTORY");
break; break;
default: // Shut up compiler warnings default: // Shut up compiler warnings
break; break;
} }
} }
// this should be scheduled even in database creation (system transaction ) // this should be scheduled even in database creation (system transaction )
switch ((RIDS) relation->rel_id) switch ((RIDS) relation->rel_id)
skipping to change at line 3547 skipping to change at line 3567
rpb->rpb_b_page = 0; rpb->rpb_b_page = 0;
rpb->rpb_b_line = 0; rpb->rpb_b_line = 0;
rpb->rpb_flags = 0; rpb->rpb_flags = 0;
rpb->rpb_transaction_nr = transaction->tra_number; rpb->rpb_transaction_nr = transaction->tra_number;
rpb->getWindow(tdbb).win_flags = 0; rpb->getWindow(tdbb).win_flags = 0;
rpb->rpb_record->pushPrecedence(PageNumber(TRANS_PAGE_SPACE, rpb->rpb_tra nsaction_nr)); rpb->rpb_record->pushPrecedence(PageNumber(TRANS_PAGE_SPACE, rpb->rpb_tra nsaction_nr));
DPM_store(tdbb, rpb, rpb->rpb_record->getPrecedence(), DPM_primary); DPM_store(tdbb, rpb, rpb->rpb_record->getPrecedence(), DPM_primary);
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES_INFO, VIO_trace(DEBUG_WRITES_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFO ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d
RMAT":%d\n", \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
if (!(transaction->tra_flags & TRA_system) && if (!(transaction->tra_flags & TRA_system) &&
transaction->tra_save_point && transaction->tra_save_point->sav_v erb_count) transaction->tra_save_point && transaction->tra_save_point->sav_v erb_count)
{ {
verb_post(tdbb, transaction, rpb, NULL, false, false); verb_post(tdbb, transaction, rpb, NULL, false, false);
} }
tdbb->bumpRelStats(RuntimeStatistics::RECORD_INSERTS, relation->rel_id); tdbb->bumpRelStats(RuntimeStatistics::RECORD_INSERTS, relation->rel_id);
skipping to change at line 3743 skipping to change at line 3763
* All changes made by the transaction are kept in one bitmap per * All changes made by the transaction are kept in one bitmap per
* relation. A second bitmap per relation tracks records for which * relation. A second bitmap per relation tracks records for which
* we have old data. The actual data is kept in a linked list stack. * we have old data. The actual data is kept in a linked list stack.
* Note that although a record may be changed several times, it will * Note that although a record may be changed several times, it will
* have only ONE old value -- the value it had before this verb * have only ONE old value -- the value it had before this verb
* started. * started.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE,
"VIO_verb_cleanup (transaction %" SQUADFORMAT")\n",
transaction ? transaction->tra_number : 0);
#endif
if (transaction->tra_flags & TRA_system) if (transaction->tra_flags & TRA_system)
return; return;
Savepoint* sav_point = transaction->tra_save_point; Savepoint* sav_point = transaction->tra_save_point;
if (!sav_point) if (!sav_point)
return; return;
Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool); Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool);
// If the current to-be-cleaned-up savepoint is very big, and the next // If the current to-be-cleaned-up savepoint is very big, and the next
skipping to change at line 3810 skipping to change at line 3825
try try
{ {
tdbb->tdbb_flags |= TDBB_verb_cleanup; tdbb->tdbb_flags |= TDBB_verb_cleanup;
tdbb->setTransaction(transaction); tdbb->setTransaction(transaction);
while ( (action = sav_point->sav_verb_actions) ) while ( (action = sav_point->sav_verb_actions) )
{ {
sav_point->sav_verb_actions = action->vct_next; sav_point->sav_verb_actions = action->vct_next;
jrd_rel* relation = action->vct_relation; jrd_rel* relation = action->vct_relation;
#ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE,
"VIO_verb_cleanup (transaction %" SQUADFORMAT", s
avepoint %" SQUADFORMAT", verb_count %u)\n",
transaction->tra_number, sav_point->sav_number, s
av_point->sav_verb_count);
#endif
if (sav_point->sav_verb_count || transaction->tra_save_po int) if (sav_point->sav_verb_count || transaction->tra_save_po int)
{ {
rpb.rpb_relation = relation; rpb.rpb_relation = relation;
rpb.rpb_number.setValue(BOF_NUMBER); rpb.rpb_number.setValue(BOF_NUMBER);
rpb.rpb_record = NULL; rpb.rpb_record = NULL;
rpb.getWindow(tdbb).win_flags = 0; rpb.getWindow(tdbb).win_flags = 0;
rpb.rpb_transaction_nr = transaction->tra_number; rpb.rpb_transaction_nr = transaction->tra_number;
if (sav_point->sav_verb_count) if (sav_point->sav_verb_count)
{ {
skipping to change at line 4010 skipping to change at line 4031
* V I O _ w r i t e l o c k * V I O _ w r i t e l o c k
* *
************************************** **************************************
* *
* Functional description * Functional description
* Modify record to make record owned by this transaction * Modify record to make record owned by this transaction
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
jrd_rel* const relation = org_rpb->rpb_relation;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_WRITES, VIO_trace(DEBUG_WRITES,
"VIO_writelock (org_rpb %" QUADFORMAT"d, transaction %" SQUADFORM "VIO_writelock (rel_id %u, org_rpb %" QUADFORMAT"d, transaction %
AT")\n", " SQUADFORMAT")\n",
org_rpb->rpb_number.getValue(), transaction ? transaction->tra_nu relation->rel_id, org_rpb->rpb_number.getValue(), transaction ? t
mber : 0); ransaction->tra_number : 0);
VIO_trace(DEBUG_WRITES_INFO, VIO_trace(DEBUG_WRITES_INFO,
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr , org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr ,
org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line, org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line,
org_rpb->rpb_f_page, org_rpb->rpb_f_line); org_rpb->rpb_f_page, org_rpb->rpb_f_line);
#endif #endif
if (transaction->tra_flags & TRA_system) if (transaction->tra_flags & TRA_system)
skipping to change at line 4055 skipping to change at line 4077
if (!org_rpb->rpb_record) if (!org_rpb->rpb_record)
{ {
Record* const org_record = VIO_record(tdbb, org_rpb, NULL, tdbb-> getDefaultPool()); Record* const org_record = VIO_record(tdbb, org_rpb, NULL, tdbb-> getDefaultPool());
org_rpb->rpb_address = org_record->getData(); org_rpb->rpb_address = org_record->getData();
const Format* const org_format = org_record->getFormat(); const Format* const org_format = org_record->getFormat();
org_rpb->rpb_length = org_format->fmt_length; org_rpb->rpb_length = org_format->fmt_length;
org_rpb->rpb_format_number = org_format->fmt_version; org_rpb->rpb_format_number = org_format->fmt_version;
} }
jrd_rel* const relation = org_rpb->rpb_relation;
// Set up the descriptor for the new record version. Initially, // Set up the descriptor for the new record version. Initially,
// it points to the same record data as the original one. // it points to the same record data as the original one.
record_param new_rpb = *org_rpb; record_param new_rpb = *org_rpb;
new_rpb.rpb_transaction_nr = transaction->tra_number; new_rpb.rpb_transaction_nr = transaction->tra_number;
AutoPtr<Record> new_record; AutoPtr<Record> new_record;
const Format* const new_format = MET_current(tdbb, relation); const Format* const new_format = MET_current(tdbb, relation);
// If the fetched record is not in the latest format, upgrade it. // If the fetched record is not in the latest format, upgrade it.
// To do that, allocate new record buffer and make the new record // To do that, allocate new record buffer and make the new record
skipping to change at line 4096 skipping to change at line 4116
switch (prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, or g_rpb, &temp, &new_rpb, switch (prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, or g_rpb, &temp, &new_rpb,
stack, true)) stack, true))
{ {
case PREPARE_CONFLICT: case PREPARE_CONFLICT:
case PREPARE_DELETE: case PREPARE_DELETE:
org_rpb->rpb_runtime_flags |= RPB_refetch; org_rpb->rpb_runtime_flags |= RPB_refetch;
return false; return false;
case PREPARE_LOCKERR: case PREPARE_LOCKERR:
// We got some kind of locking error (deadlock, timeout o r lock_conflict) // We got some kind of locking error (deadlock, timeout o r lock_conflict)
// Error details should be stuffed into status vector at this point // Error details should be stuffed into status vector at this point
ERR_post(Arg::Gds(isc_concurrent_transaction) << Arg::Num // hvlad: we have no details as TRA_wait has already clea
(org_rpb->rpb_transaction_nr)); red the status vector
ERR_post(Arg::Gds(isc_deadlock) <<
Arg::Gds(isc_update_conflict) <<
Arg::Gds(isc_concurrent_transaction) <<
Arg::Num(org_rpb->rpb_transaction_nr));
} }
// Old record was restored and re-fetched for write. Now replace it. // Old record was restored and re-fetched for write. Now replace it.
org_rpb->rpb_transaction_nr = new_rpb.rpb_transaction_nr; org_rpb->rpb_transaction_nr = new_rpb.rpb_transaction_nr;
org_rpb->rpb_format_number = new_rpb.rpb_format_number; org_rpb->rpb_format_number = new_rpb.rpb_format_number;
org_rpb->rpb_b_page = temp.rpb_page; org_rpb->rpb_b_page = temp.rpb_page;
org_rpb->rpb_b_line = temp.rpb_line; org_rpb->rpb_b_line = temp.rpb_line;
org_rpb->rpb_address = new_rpb.rpb_address; org_rpb->rpb_address = new_rpb.rpb_address;
org_rpb->rpb_length = new_rpb.rpb_length; org_rpb->rpb_length = new_rpb.rpb_length;
org_rpb->rpb_flags |= rpb_delta; org_rpb->rpb_flags &= ~(rpb_delta | rpb_uk_modified);
org_rpb->rpb_flags |= new_rpb.rpb_flags & rpb_delta;
replace_record(tdbb, org_rpb, &stack, transaction); replace_record(tdbb, org_rpb, &stack, transaction);
if (!(transaction->tra_flags & TRA_system) && transaction->tra_save_point ) if (!(transaction->tra_flags & TRA_system) && transaction->tra_save_point )
verb_post(tdbb, transaction, org_rpb, NULL, false, false); verb_post(tdbb, transaction, org_rpb, NULL, false, false);
// for an autocommit transaction, mark a commit as necessary // for an autocommit transaction, mark a commit as necessary
if (transaction->tra_flags & TRA_autocommit) if (transaction->tra_flags & TRA_autocommit)
transaction->tra_flags |= TRA_perform_autocommit; transaction->tra_flags |= TRA_perform_autocommit;
skipping to change at line 4366 skipping to change at line 4390
* Functional description * Functional description
* Delete a record an all of its fragments. This assumes the * Delete a record an all of its fragments. This assumes the
* record has already been fetched for write. If a pool is given, * record has already been fetched for write. If a pool is given,
* the caller has requested that data be fetched as the record is * the caller has requested that data be fetched as the record is
* deleted. * deleted.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES, VIO_trace(DEBUG_WRITES,
"delete_record (record_param %" QUADFORMAT"d, prior_page %" SLONG "delete_record (rel_id %u, record_param %" QUADFORMAT"d, prior_pa
FORMAT", pool %p)\n", ge %" SLONGFORMAT", pool %p)\n",
rpb->rpb_number.getValue(), prior_page, (void*) pool); relation->rel_id, rpb->rpb_number.getValue(), prior_page, (void*)
pool);
VIO_trace(DEBUG_WRITES_INFO, VIO_trace(DEBUG_WRITES_INFO,
" delete_record record %" SLONGFORMAT":%d, rpb_trans %" SQUADF ORMAT " delete_record record %" SLONGFORMAT":%d, rpb_trans %" SQUADF ORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
UCHAR* tail; UCHAR* tail;
const UCHAR* tail_end; const UCHAR* tail_end;
skipping to change at line 4442 skipping to change at line 4467
************************************** **************************************
* *
* Functional description * Functional description
* Delete the tail of a record. If no tail, don't do nuttin'. * Delete the tail of a record. If no tail, don't do nuttin'.
* If the address of a record tail has been passed, fetch data. * If the address of a record tail has been passed, fetch data.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES, VIO_trace(DEBUG_WRITES,
"delete_tail (record_param %" QUADFORMAT"d, prior_page %" SLONGFO "delete_tail (rel_id %u, record_param %" QUADFORMAT"d, prior_page
RMAT", tail %p, tail_end %p)\n", %" SLONGFORMAT", tail %p, tail_end %p)\n",
rpb->rpb_number.getValue(), prior_page, tail, tail_end); relation->rel_id, rpb->rpb_number.getValue(), prior_page, tail, t
ail_end);
VIO_trace(DEBUG_WRITES_INFO, VIO_trace(DEBUG_WRITES_INFO,
" tail of record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " tail of record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
RuntimeStatistics::Accumulator fragments(tdbb, rpb->rpb_relation, RuntimeStatistics::Accumulator fragments(tdbb, rpb->rpb_relation,
skipping to change at line 4528 skipping to change at line 4554
* and all of the ancestors. Be particulary careful since this * and all of the ancestors. Be particulary careful since this
* can do a lot of damage. * can do a lot of damage.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
Jrd::Attachment* attachment = transaction->tra_attachment; Jrd::Attachment* attachment = transaction->tra_attachment;
fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation)); fb_assert(assert_gc_enabled(transaction, rpb->rpb_relation));
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES, VIO_trace(DEBUG_WRITES,
"expunge (record_param %" QUADFORMAT"d, transaction %" SQUADFORMA T "expunge (rel_id %u, record_param %" QUADFORMAT"d, transaction %" SQUADFORMAT
", prior_page %" SLONGFORMAT")\n", ", prior_page %" SLONGFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0, relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans action->tra_number : 0,
prior_page); prior_page);
#endif #endif
if (attachment->att_flags & ATT_no_cleanup) if (attachment->att_flags & ATT_no_cleanup)
return; return;
// Re-fetch the record // Re-fetch the record
if (!DPM_get(tdbb, rpb, LCK_write)) if (!DPM_get(tdbb, rpb, LCK_write))
{ {
skipping to change at line 4612 skipping to change at line 4639
* 1) just been deleted or * 1) just been deleted or
* 2) just had its back pointers set to zero * 2) just had its back pointers set to zero
* Therefor we can do a fetch on the back pointers we've got * Therefor we can do a fetch on the back pointers we've got
* because we have the last existing copy of them. * because we have the last existing copy of them.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_WRITES, VIO_trace(DEBUG_WRITES,
"garbage_collect (record_param %" QUADFORMAT"d, prior_page %" SLO "garbage_collect (rel_id %u, record_param %" QUADFORMAT"d, prior_
NGFORMAT", staying)\n", page %" SLONGFORMAT", staying)\n",
rpb->rpb_number.getValue(), prior_page); relation->rel_id, rpb->rpb_number.getValue(), prior_page);
VIO_trace(DEBUG_WRITES_INFO, VIO_trace(DEBUG_WRITES_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
RuntimeStatistics::Accumulator backversions(tdbb, rpb->rpb_relation, RuntimeStatistics::Accumulator backversions(tdbb, rpb->rpb_relation,
skipping to change at line 5461 skipping to change at line 5489
* *
* Functional description * Functional description
* Prepare for a modify or erase. Store the old version * Prepare for a modify or erase. Store the old version
* of a record, fetch the current version, check transaction * of a record, fetch the current version, check transaction
* states, etc. * states, etc.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment(); Attachment* const attachment = tdbb->getAttachment();
jrd_rel* const relation = rpb->rpb_relation;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL, VIO_trace(DEBUG_TRACE_ALL,
"prepare_update (transaction %" SQUADFORMAT "prepare_update (rel_id %u, transaction %" SQUADFORMAT
", commit_tid read %" SQUADFORMAT", record_param %" QUADFORMAT"d, ", ", commit_tid read %" SQUADFORMAT", record_param %" QUADFORMAT"d, ",
transaction ? transaction->tra_number : 0, commit_tid_read, relation->rel_id, transaction ? transaction->tra_number : 0, comm it_tid_read,
rpb ? rpb->rpb_number.getValue() : 0); rpb ? rpb->rpb_number.getValue() : 0);
VIO_trace(DEBUG_TRACE_ALL, VIO_trace(DEBUG_TRACE_ALL,
" temp_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d, stack)\n", " temp_rpb %" QUADFORMAT"d, new_rpb %" QUADFORMAT"d, stack)\n",
temp ? temp->rpb_number.getValue() : 0, temp ? temp->rpb_number.getValue() : 0,
new_rpb ? new_rpb->rpb_number.getValue() : 0); new_rpb ? new_rpb->rpb_number.getValue() : 0);
VIO_trace(DEBUG_TRACE_ALL_INFO, VIO_trace(DEBUG_TRACE_ALL_INFO,
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT
skipping to change at line 5500 skipping to change at line 5529
return an update conflict. If the transaction is dead, back out the return an update conflict. If the transaction is dead, back out the
old version of the record and try again. If in limbo, punt. old version of the record and try again. If in limbo, punt.
The above is true only for concurrency & consistency mode transactions. The above is true only for concurrency & consistency mode transactions.
For read committed transactions, check if the latest commited version For read committed transactions, check if the latest commited version
is the same as the version that was read for the update. If yes, is the same as the version that was read for the update. If yes,
the update can take place. If some other transaction has modified the update can take place. If some other transaction has modified
the record and committed, then an update error will be returned. the record and committed, then an update error will be returned.
*/ */
jrd_rel* const relation = rpb->rpb_relation;
*temp = *rpb; *temp = *rpb;
Record* const record = rpb->rpb_record; Record* const record = rpb->rpb_record;
// Mark the record as chained version, and re-store it // Mark the record as chained version, and re-store it
temp->rpb_address = record->getData(); temp->rpb_address = record->getData();
const Format* const format = record->getFormat(); const Format* const format = record->getFormat();
temp->rpb_length = format->fmt_length; temp->rpb_length = format->fmt_length;
temp->rpb_format_number = format->fmt_version; temp->rpb_format_number = format->fmt_version;
temp->rpb_flags = rpb_chained; temp->rpb_flags = rpb_chained;
skipping to change at line 5768 skipping to change at line 5795
tdbb->bumpRelStats(RuntimeStatistics::REC ORD_CONFLICTS, relation->rel_id); tdbb->bumpRelStats(RuntimeStatistics::REC ORD_CONFLICTS, relation->rel_id);
ERR_post(Arg::Gds(isc_deadlock) << ERR_post(Arg::Gds(isc_deadlock) <<
Arg::Gds(isc_update_conf lict) << Arg::Gds(isc_update_conf lict) <<
Arg::Gds(isc_concurrent_ transaction) << Arg::Num(update_conflict_trans)); Arg::Gds(isc_concurrent_ transaction) << Arg::Num(update_conflict_trans));
} }
case tra_active: case tra_active:
return PREPARE_LOCKERR; return PREPARE_LOCKERR;
case tra_limbo: case tra_limbo:
ERR_post(Arg::Gds(isc_deadlock) << Arg::Gds(isc_t rainlim)); ERR_post(Arg::Gds(isc_trainlim) << Arg::Gds(isc_r ec_in_limbo) << Arg::Num(rpb->rpb_transaction_nr));
case tra_dead: case tra_dead:
break; break;
default: default:
fb_assert(false); fb_assert(false);
} // switch (state) } // switch (state)
break; break;
skipping to change at line 5877 skipping to change at line 5904
* if the purge couldn't happen because somebody else had the record. * if the purge couldn't happen because somebody else had the record.
* But the function was made void since nobody checks its return value. * But the function was made void since nobody checks its return value.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase(); Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb); CHECK_DBB(dbb);
fb_assert(assert_gc_enabled(tdbb->getTransaction(), rpb->rpb_relation)); fb_assert(assert_gc_enabled(tdbb->getTransaction(), rpb->rpb_relation));
jrd_rel* const relation = rpb->rpb_relation;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL, VIO_trace(DEBUG_TRACE_ALL,
"purge (record_param %" QUADFORMAT"d)\n", rpb->rpb_number.getValu "purge (rel_id %u, record_param %" QUADFORMAT"d)\n",
e()); relation->rel_id, rpb->rpb_number.getValue());
VIO_trace(DEBUG_TRACE_ALL_INFO, VIO_trace(DEBUG_TRACE_ALL_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line); rpb->rpb_f_page, rpb->rpb_f_line);
#endif #endif
// Release and re-fetch the page for write. Make sure it's still the // Release and re-fetch the page for write. Make sure it's still the
// same record (give up if not). Then zap the back pointer and release // same record (give up if not). Then zap the back pointer and release
// the record. // the record.
record_param temp = *rpb; record_param temp = *rpb;
jrd_rel* const relation = rpb->rpb_relation;
AutoGCRecord gc_rec(VIO_gc_record(tdbb, relation)); AutoGCRecord gc_rec(VIO_gc_record(tdbb, relation));
Record* record = rpb->rpb_record = gc_rec; Record* record = rpb->rpb_record = gc_rec;
VIO_data(tdbb, rpb, relation->rel_pool); VIO_data(tdbb, rpb, relation->rel_pool);
temp.rpb_prior = rpb->rpb_prior; temp.rpb_prior = rpb->rpb_prior;
rpb->rpb_record = temp.rpb_record; rpb->rpb_record = temp.rpb_record;
if (!DPM_get(tdbb, rpb, LCK_write)) if (!DPM_get(tdbb, rpb, LCK_write))
{ {
skipping to change at line 5955 skipping to change at line 5983
************************************** **************************************
* *
* Functional description * Functional description
* Replace a record and get rid of the old tail, if any. If requested, * Replace a record and get rid of the old tail, if any. If requested,
* fetch data for the record on the way out. * fetch data for the record on the way out.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
jrd_rel* relation = rpb->rpb_relation;
VIO_trace(DEBUG_TRACE_ALL, VIO_trace(DEBUG_TRACE_ALL,
"replace_record (record_param %" QUADFORMAT"d, transaction %" SQU "replace_record (rel_id %u, record_param %" QUADFORMAT"d, transac
ADFORMAT")\n", tion %" SQUADFORMAT")\n",
rpb->rpb_number.getValue(), transaction ? transaction->tra_number relation->rel_id, rpb->rpb_number.getValue(), transaction ? trans
: 0); action->tra_number : 0);
VIO_trace(DEBUG_TRACE_ALL_INFO, VIO_trace(DEBUG_TRACE_ALL_INFO,
" record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT
":%d, prior %p\n", ":%d, prior %p\n",
rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr, rpb->rpb_page, rpb->rpb_line, rpb->rpb_transaction_nr,
rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line,
rpb->rpb_f_page, rpb->rpb_f_line, (void*) rpb->rpb_prior); rpb->rpb_f_page, rpb->rpb_f_line, (void*) rpb->rpb_prior);
#endif #endif
skipping to change at line 6085 skipping to change at line 6114
return MOV_get_long(&desc1, 0); return MOV_get_long(&desc1, 0);
SSHORT value = (SSHORT) DYN_UTIL_gen_unique_id(tdbb, dyn_id, name); SSHORT value = (SSHORT) DYN_UTIL_gen_unique_id(tdbb, dyn_id, name);
dsc desc2; dsc desc2;
desc2.makeShort(0, &value); desc2.makeShort(0, &value);
MOV_move(tdbb, &desc2, &desc1); MOV_move(tdbb, &desc2, &desc1);
record->clearNull(field_id); record->clearNull(field_id);
return value; return value;
} }
// Assign the 31-bit auto generated ID to a particular field
static void set_nbackup_id(thread_db* tdbb, Record* record, USHORT field_id, drq
_type_t dyn_id,
const char* name)
{
dsc desc1;
if (EVL_field(0, record, field_id, &desc1))
return;
SLONG value = (SLONG) DYN_UTIL_gen_unique_id(tdbb, dyn_id, name);
dsc desc2;
desc2.makeLong(0, &value);
MOV_move(tdbb, &desc2, &desc1);
record->clearNull(field_id);
}
static void set_owner_name(thread_db* tdbb, Record* record, USHORT field_id) static void set_owner_name(thread_db* tdbb, Record* record, USHORT field_id)
{ {
/************************************** /**************************************
* *
* s e t _ o w n e r _ n a m e * s e t _ o w n e r _ n a m e
* *
************************************** **************************************
* *
* Functional description * Functional description
* Set the owner name for the metadata object. * Set the owner name for the metadata object.
skipping to change at line 6182 skipping to change at line 6227
* *
* Functional description * Functional description
* Modify a record in place. This is used for system transactions * Modify a record in place. This is used for system transactions
* and for multiple modifications of a user record. * and for multiple modifications of a user record.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase(); Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb); CHECK_DBB(dbb);
jrd_rel* const relation = org_rpb->rpb_relation;
#ifdef VIO_DEBUG #ifdef VIO_DEBUG
VIO_trace(DEBUG_TRACE_ALL, VIO_trace(DEBUG_TRACE_ALL,
"update_in_place (transaction %" SQUADFORMAT", org_rpb %" QUADFOR MAT"d, " "update_in_place (rel_id %u, transaction %" SQUADFORMAT", org_rpb %" QUADFORMAT"d, "
"new_rpb %" QUADFORMAT"d)\n", "new_rpb %" QUADFORMAT"d)\n",
transaction ? transaction->tra_number : 0, org_rpb->rpb_number.ge tValue(), relation->rel_id, transaction ? transaction->tra_number : 0, org_ rpb->rpb_number.getValue(),
new_rpb ? new_rpb->rpb_number.getValue() : 0); new_rpb ? new_rpb->rpb_number.getValue() : 0);
VIO_trace(DEBUG_TRACE_ALL_INFO, VIO_trace(DEBUG_TRACE_ALL_INFO,
" old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT " old record %" SLONGFORMAT":%d, rpb_trans %" SQUADFORMAT
", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n", ", flags %d, back %" SLONGFORMAT":%d, fragment %" SLONGFORMAT":%d \n",
org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr , org_rpb->rpb_page, org_rpb->rpb_line, org_rpb->rpb_transaction_nr ,
org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line, org_rpb->rpb_flags, org_rpb->rpb_b_page, org_rpb->rpb_b_line,
org_rpb->rpb_f_page, org_rpb->rpb_f_line); org_rpb->rpb_f_page, org_rpb->rpb_f_line);
#endif #endif
PageStack& stack = new_rpb->rpb_record->getPrecedence(); PageStack& stack = new_rpb->rpb_record->getPrecedence();
jrd_rel* const relation = org_rpb->rpb_relation;
Record* const old_data = org_rpb->rpb_record; Record* const old_data = org_rpb->rpb_record;
// If the old version has been stored as a delta, things get complicated. Clearly, // If the old version has been stored as a delta, things get complicated. Clearly,
// if we overwrite the current record, the differences from the current v ersion // if we overwrite the current record, the differences from the current v ersion
// becomes meaningless. What we need to do is replace the old "delta" re cord // becomes meaningless. What we need to do is replace the old "delta" re cord
// with an old "complete" record, update in placement, then delete the ol d delta record // with an old "complete" record, update in placement, then delete the ol d delta record
AutoGCRecord gc_rec; AutoGCRecord gc_rec;
record_param temp2; record_param temp2;
skipping to change at line 6326 skipping to change at line 6371
* (i.e. update_in_place). * (i.e. update_in_place).
* new_rpb: Only used to pass to garbage_collect_idx but that functio n doesn't use it! * new_rpb: Only used to pass to garbage_collect_idx but that functio n doesn't use it!
* same_tx: true if this transaction inserted/updated this record * same_tx: true if this transaction inserted/updated this record
* and then deleted it. * and then deleted it.
* false in all other cases. * false in all other cases.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool); Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool);
MemoryPool* pool = tdbb->getDefaultPool();
// Find action block for relation // Find action block for relation
VerbAction* action; VerbAction* action;
for (action = transaction->tra_save_point->sav_verb_actions; action; acti on = action->vct_next) for (action = transaction->tra_save_point->sav_verb_actions; action; acti on = action->vct_next)
{ {
if (action->vct_relation == rpb->rpb_relation) if (action->vct_relation == rpb->rpb_relation)
break; break;
} }
if (!action) if (!action)
{ {
if ( (action = transaction->tra_save_point->sav_verb_free) ) if ( (action = transaction->tra_save_point->sav_verb_free) )
transaction->tra_save_point->sav_verb_free = action->vct_ next; transaction->tra_save_point->sav_verb_free = action->vct_ next;
else else
action = FB_NEW_POOL(*tdbb->getDefaultPool()) VerbAction( ); action = FB_NEW_POOL(*pool) VerbAction();
action->vct_next = transaction->tra_save_point->sav_verb_actions; action->vct_next = transaction->tra_save_point->sav_verb_actions;
transaction->tra_save_point->sav_verb_actions = action; transaction->tra_save_point->sav_verb_actions = action;
action->vct_relation = rpb->rpb_relation; action->vct_relation = rpb->rpb_relation;
} }
if (!RecordBitmap::test(action->vct_records, rpb->rpb_number.getValue())) if (!RecordBitmap::test(action->vct_records, rpb->rpb_number.getValue()))
{ {
RBM_SET(tdbb->getDefaultPool(), &action->vct_records, rpb->rpb_nu mber.getValue()); RBM_SET(pool, &action->vct_records, rpb->rpb_number.getValue());
if (old_data) if (old_data)
{ {
// An update-in-place is being posted to this savepoint, and this // An update-in-place is being posted to this savepoint, and this
// savepoint hasn't seen this record before. // savepoint hasn't seen this record before.
if (!action->vct_undo) if (!action->vct_undo)
action->vct_undo = FB_NEW UndoItemTree(tdbb->getD efaultPool()); action->vct_undo = FB_NEW_POOL(*pool) UndoItemTre e(pool);
action->vct_undo->add(UndoItem(transaction, rpb->rpb_numb er, old_data, same_tx, false)); action->vct_undo->add(UndoItem(transaction, rpb->rpb_numb er, old_data, same_tx, false));
} }
else if (same_tx) else if (same_tx)
{ {
// An insert/update followed by a delete is posted to thi s savepoint, // An insert/update followed by a delete is posted to thi s savepoint,
// and this savepoint hasn't seen this record before. // and this savepoint hasn't seen this record before.
if (!action->vct_undo) if (!action->vct_undo)
action->vct_undo = FB_NEW UndoItemTree(tdbb->getD efaultPool()); action->vct_undo = FB_NEW_POOL(*pool) UndoItemTre e(pool);
action->vct_undo->add(UndoItem(rpb->rpb_number, true, new _ver)); action->vct_undo->add(UndoItem(rpb->rpb_number, true, new _ver));
} }
} }
else if (same_tx) else if (same_tx)
{ {
AutoUndoRecord undo; AutoUndoRecord undo;
if (action->vct_undo && action->vct_undo->locate(rpb->rpb_number. getValue())) if (action->vct_undo && action->vct_undo->locate(rpb->rpb_number. getValue()))
{ {
skipping to change at line 6390 skipping to change at line 6436
action->vct_undo->current().markSameTx(); action->vct_undo->current().markSameTx();
undo = action->vct_undo->current().setupRecord(transactio n); undo = action->vct_undo->current().setupRecord(transactio n);
} }
else else
{ {
// An insert/update followed by a delete is posted to thi s savepoint, // An insert/update followed by a delete is posted to thi s savepoint,
// and this savepoint has seen this record before but it doesn't have undo data. // and this savepoint has seen this record before but it doesn't have undo data.
if (!action->vct_undo) if (!action->vct_undo)
action->vct_undo = FB_NEW UndoItemTree(tdbb->getD efaultPool()); action->vct_undo = FB_NEW_POOL(*pool) UndoItemTre e(pool);
action->vct_undo->add(UndoItem(rpb->rpb_number, true, tru e)); action->vct_undo->add(UndoItem(rpb->rpb_number, true, tru e));
} }
if (old_data) if (old_data)
{ {
// The passed old_data will not be used. Thus, garbage c ollect. // The passed old_data will not be used. Thus, garbage c ollect.
garbage_collect_idx(tdbb, rpb, old_data, undo); garbage_collect_idx(tdbb, rpb, old_data, undo);
} }
 End of changes. 80 change blocks. 
104 lines changed or deleted 163 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)