mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 22:03:03 +01:00
The files rng.cpp, rng.h, rng_proto.h, bookmark.cpp and bookmark.h belong exclusively to PC_ENGINE, that's obsolete functionality.
Sixth step: remove the places protected by the macro PC_ENGINE. More to come. (I guess all of you who have pending functional changes to post will love this commit. <g>)
This commit is contained in:
parent
7c90e51ce7
commit
2b99e764e3
239
src/jrd/cmp.cpp
239
src/jrd/cmp.cpp
@ -148,10 +148,6 @@ static bool stream_in_rse(USHORT, RecordSelExpr*);
|
||||
static void build_external_access(thread_db* tdbb, ExternalAccessList& list, jrd_req* request);
|
||||
static void verify_trigger_access(thread_db* tdbb, jrd_rel* owner_relation, trig_vec* triggers, jrd_rel* view);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static USHORT base_stream(CompilerScratch*, jrd_nod**, bool);
|
||||
#endif
|
||||
|
||||
#ifdef CMP_DEBUG
|
||||
IMPLEMENT_TRACE_ROUTINE(cmp_trace, "CMP")
|
||||
#endif
|
||||
@ -876,13 +872,6 @@ void CMP_get_desc(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node, DSC * de
|
||||
case nod_count:
|
||||
case nod_gen_id:
|
||||
case nod_lock_state:
|
||||
#ifdef PC_ENGINE
|
||||
case nod_lock_record:
|
||||
case nod_lock_relation:
|
||||
case nod_seek:
|
||||
case nod_seek_no_warn:
|
||||
case nod_crack:
|
||||
#endif
|
||||
desc->dsc_dtype = dtype_long;
|
||||
desc->dsc_length = sizeof(SLONG);
|
||||
desc->dsc_scale = 0;
|
||||
@ -890,16 +879,6 @@ void CMP_get_desc(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node, DSC * de
|
||||
desc->dsc_flags = 0;
|
||||
return;
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
case nod_begin_range:
|
||||
desc->dsc_dtype = dtype_text;
|
||||
desc->dsc_ttype() = ttype_ascii;
|
||||
desc->dsc_scale = 0;
|
||||
desc->dsc_length = RANGE_NAME_LENGTH;
|
||||
desc->dsc_flags = 0;
|
||||
return;
|
||||
#endif
|
||||
|
||||
case nod_field:
|
||||
{
|
||||
const USHORT id = (USHORT) (IPTR) node->nod_arg[e_fld_id];
|
||||
@ -2183,39 +2162,6 @@ void CMP_post_resource( ResourceList* rsc_ptr,
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void CMP_release_resource(ResourceList* rsc_ptr, enum Resource::rsc_s type, USHORT id)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* C M P _ r e l e a s e _ r e s o u r c e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Release resource from request.
|
||||
*
|
||||
* 10-Apr-2004, Nickolay Samofatov
|
||||
* This code is broken because it doesn't account case when resource is used more than once
|
||||
*
|
||||
**************************************/
|
||||
Resource* resource;
|
||||
for (; (resource = *rsc_ptr); rsc_ptr = &resource->rsc_next) {
|
||||
if (resource->rsc_type == type && resource->rsc_id == id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!resource)
|
||||
return;
|
||||
|
||||
// take out of the linked list and release
|
||||
|
||||
*rsc_ptr = resource->rsc_next;
|
||||
delete resource;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void CMP_decrement_prc_use_count(thread_db* tdbb, jrd_prc* procedure)
|
||||
{
|
||||
/*********************************************
|
||||
@ -2327,10 +2273,6 @@ void CMP_release(thread_db* tdbb, jrd_req* request)
|
||||
|
||||
EXE_unwind(tdbb, request);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
RNG_release_ranges(request);
|
||||
#endif
|
||||
|
||||
if (request->req_attachment) {
|
||||
for (jrd_req** next = &request->req_attachment->att_requests;
|
||||
*next; next = &(*next)->req_request)
|
||||
@ -2455,54 +2397,6 @@ static UCHAR* alloc_map(thread_db* tdbb, CompilerScratch* csb, USHORT stream)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static USHORT base_stream(CompilerScratch* csb, jrd_nod** stream_number, bool nav_stream)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* b a s e _ s t r e a m
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Find the base stream of a view for navigational
|
||||
* access. If there is more than one base table,
|
||||
* give an error.
|
||||
*
|
||||
**************************************/
|
||||
DEV_BLKCHK(csb, type_csb);
|
||||
|
||||
// note: *stream_number is NOT a jrd_nod*
|
||||
USHORT stream = (USHORT) *stream_number;
|
||||
|
||||
// if the stream references a view, follow map
|
||||
|
||||
UCHAR* map = csb->csb_rpt[stream].csb_map;
|
||||
if (map) {
|
||||
if (map[2]) {
|
||||
if (nav_stream) {
|
||||
// navigational stream %ld references a view with more than one base table
|
||||
ERR_post(isc_complex_view, isc_arg_number, (SLONG) stream, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
map++;
|
||||
stream = *map;
|
||||
}
|
||||
}
|
||||
|
||||
// if this is a navigational stream, fix up the stream number
|
||||
// in the node tree to point to the base table from now on
|
||||
|
||||
if (nav_stream) {
|
||||
*stream_number = (jrd_nod*) stream;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static jrd_nod* catenate_nodes(thread_db* tdbb, NodeStack& stack)
|
||||
{
|
||||
/**************************************
|
||||
@ -4771,121 +4665,6 @@ static jrd_nod* pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
// the remainder of the node types are for IDAPI support:
|
||||
// fix up the stream to point to the base table, and preserve
|
||||
// the pointers to the navigational rsb for easy reference
|
||||
// later during execution
|
||||
|
||||
case nod_stream:
|
||||
{
|
||||
RecordSelExpr* rse = (RecordSelExpr*) node;
|
||||
rse_node = node;
|
||||
// setting the stream flag will allow the optimizer to
|
||||
// detect that a SET INDEX may be done on this stream
|
||||
rse_node->nod_flags |= rse_stream;
|
||||
rsb_ptr = &rse->rse_rsb;
|
||||
jrd_nod* relation = rse->rse_relation[0];
|
||||
stream = base_stream(csb, &relation->nod_arg[e_rel_stream], true);
|
||||
csb->csb_rpt[stream].csb_rsb_ptr = &rse->rse_rsb;
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_find:
|
||||
stream = base_stream(csb, &node->nod_arg[e_find_stream], true);
|
||||
if (!(node->nod_arg[e_find_rsb] =
|
||||
(jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr))
|
||||
{
|
||||
ERR_post(isc_stream_not_defined, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_find_dbkey:
|
||||
case nod_find_dbkey_version:
|
||||
stream = base_stream(csb, &node->nod_arg[e_find_dbkey_stream], true);
|
||||
if (!(node->nod_arg[e_find_dbkey_rsb] =
|
||||
(jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr))
|
||||
{
|
||||
ERR_post(isc_stream_not_defined, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_set_index:
|
||||
stream = base_stream(csb, &node->nod_arg[e_index_stream], true);
|
||||
if (!(node->nod_arg[e_index_rsb] =
|
||||
(jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr))
|
||||
{
|
||||
ERR_post(isc_stream_not_defined, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_get_bookmark:
|
||||
stream = base_stream(csb, &node->nod_arg[e_getmark_stream], true);
|
||||
if (!(node->nod_arg[e_getmark_rsb] =
|
||||
(jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr))
|
||||
{
|
||||
ERR_post(isc_stream_not_defined, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_set_bookmark:
|
||||
stream = base_stream(csb, &node->nod_arg[e_setmark_stream], true);
|
||||
if (!(node->nod_arg[e_setmark_rsb] =
|
||||
(jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr))
|
||||
{
|
||||
ERR_post(isc_stream_not_defined, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_lock_record:
|
||||
stream = base_stream(csb, &node->nod_arg[e_lockrec_stream], true);
|
||||
if (!(node->nod_arg[e_lockrec_rsb] =
|
||||
(jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr))
|
||||
{
|
||||
ERR_post(isc_stream_not_defined, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_crack:
|
||||
case nod_force_crack:
|
||||
stream = base_stream(csb, &node->nod_arg[0], true);
|
||||
if (!(node->nod_arg[1] = (jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr))
|
||||
ERR_post(isc_stream_not_defined, 0);
|
||||
break;
|
||||
|
||||
case nod_reset_stream:
|
||||
stream = base_stream(csb, &node->nod_arg[e_reset_from_stream], true);
|
||||
if (!(node->nod_arg[e_reset_from_rsb] =
|
||||
(jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr))
|
||||
{
|
||||
ERR_post(isc_stream_not_defined, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case nod_cardinality:
|
||||
stream = base_stream(csb, &node->nod_arg[e_card_stream], true);
|
||||
if (!(node->nod_arg[e_card_rsb] =
|
||||
(jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr))
|
||||
{
|
||||
ERR_post(isc_stream_not_defined, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
// the following DML nodes need to have their rsb's stored when
|
||||
// they are referencing a navigational stream, so that we can
|
||||
// follow proper IDAPI semantics in manipulating a stream
|
||||
|
||||
case nod_erase:
|
||||
stream = base_stream(csb, &node->nod_arg[e_erase_stream], false);
|
||||
node->nod_arg[e_erase_rsb] = (jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr;
|
||||
break;
|
||||
|
||||
case nod_modify:
|
||||
stream = base_stream(csb, &node->nod_arg[e_mod_org_stream], false);
|
||||
node->nod_arg[e_mod_rsb] = (jrd_nod*) csb->csb_rpt[stream].csb_rsb_ptr;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -5080,10 +4859,6 @@ static jrd_nod* pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node
|
||||
case nod_lowcase:
|
||||
case nod_prot_mask:
|
||||
case nod_lock_state:
|
||||
#ifdef PC_ENGINE
|
||||
case nod_lock_record:
|
||||
case nod_lock_relation:
|
||||
#endif
|
||||
case nod_scalar:
|
||||
case nod_cast:
|
||||
case nod_extract:
|
||||
@ -5091,13 +4866,6 @@ static jrd_nod* pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node
|
||||
case nod_current_time:
|
||||
case nod_current_timestamp:
|
||||
case nod_current_date:
|
||||
#ifdef PC_ENGINE
|
||||
case nod_cardinality:
|
||||
case nod_seek:
|
||||
case nod_seek_no_warn:
|
||||
case nod_crack:
|
||||
case nod_begin_range:
|
||||
#endif
|
||||
{
|
||||
dsc descriptor_a;
|
||||
CMP_get_desc(tdbb, csb, node, &descriptor_a);
|
||||
@ -5704,13 +5472,6 @@ static RecordSource* post_rse(thread_db* tdbb, CompilerScratch* csb, RecordSelEx
|
||||
rsb->rsb_flags |= rsb_singular;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
// this flag lets the VIO layer know to add a page to the cache range
|
||||
if (rse->nod_flags & rse_stream) {
|
||||
rsb->rsb_flags |= rsb_stream_type;
|
||||
}
|
||||
#endif
|
||||
|
||||
// mark all the substreams as inactive
|
||||
|
||||
jrd_nod** ptr = rse->rse_relation;
|
||||
|
@ -45,9 +45,6 @@ Jrd::jrd_req* CMP_make_request(Jrd::thread_db*, Jrd::CompilerScratch*);
|
||||
void CMP_post_access(Jrd::thread_db*, Jrd::CompilerScratch*, const Firebird::MetaName&, SLONG,
|
||||
Jrd::SecurityClass::flags_t, const TEXT*, const Firebird::MetaName&);
|
||||
void CMP_post_resource(Jrd::ResourceList*, blk*, Jrd::Resource::rsc_s, USHORT);
|
||||
#ifdef PC_ENGINE
|
||||
void CMP_release_resource(Jrd::ResourceList&, Jrd::Resource::rsc_s, USHORT);
|
||||
#endif
|
||||
void CMP_release(Jrd::thread_db*, Jrd::jrd_req*);
|
||||
void CMP_shutdown_database(Jrd::thread_db*);
|
||||
void CMP_verify_access(Jrd::thread_db* tdbb, Jrd::jrd_req* request);
|
||||
|
191
src/jrd/evl.cpp
191
src/jrd/evl.cpp
@ -152,10 +152,6 @@ static SINT64 get_day_fraction(const dsc* d);
|
||||
static dsc* get_mask(thread_db*, jrd_nod*, impure_value*);
|
||||
static SINT64 get_timestamp_to_isc_ticks(const dsc* d);
|
||||
static void init_agg_distinct(thread_db*, const jrd_nod*);
|
||||
#ifdef PC_ENGINE
|
||||
static dsc* lock_record(thread_db*, jrd_nod*, impure_value*);
|
||||
static dsc* lock_relation(thread_db*, jrd_nod*, impure_value*);
|
||||
#endif
|
||||
static dsc* lock_state(thread_db*, jrd_nod*, impure_value*);
|
||||
static dsc* multiply(const dsc*, impure_value*, const jrd_nod*);
|
||||
static dsc* multiply2(const dsc*, impure_value*, const jrd_nod*);
|
||||
@ -893,16 +889,7 @@ dsc* EVL_expr(thread_db* tdbb, jrd_nod* const node)
|
||||
|
||||
case nod_lock_state:
|
||||
return lock_state(tdbb, node, impure);
|
||||
#ifdef PC_ENGINE
|
||||
case nod_lock_record:
|
||||
return lock_record(tdbb, node, impure);
|
||||
|
||||
case nod_lock_relation:
|
||||
return lock_relation(tdbb, node, impure);
|
||||
|
||||
case nod_begin_range:
|
||||
return RNG_begin(node, impure);
|
||||
#endif
|
||||
case nod_null:
|
||||
request->req_flags |= req_null;
|
||||
return NULL;
|
||||
@ -1039,46 +1026,6 @@ dsc* EVL_expr(thread_db* tdbb, jrd_nod* const node)
|
||||
case nod_trim:
|
||||
return trim(tdbb, node, impure);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
case nod_crack:
|
||||
{
|
||||
RecordSource* rsb = *(RecordSource**) node->nod_arg[1];
|
||||
if (rsb->rsb_type == rsb_boolean)
|
||||
rsb = rsb->rsb_next;
|
||||
IRSB irsb = (IRSB) ((UCHAR *) request + rsb->rsb_impure);
|
||||
impure->vlu_desc.dsc_address =
|
||||
(UCHAR *) & impure->vlu_misc.vlu_long;
|
||||
impure->vlu_desc.dsc_dtype = dtype_long;
|
||||
impure->vlu_desc.dsc_length = sizeof(ULONG);
|
||||
impure->vlu_desc.dsc_scale = 0;
|
||||
impure->vlu_misc.vlu_long =
|
||||
irsb->irsb_flags & (irsb_bof | irsb_eof | irsb_crack);
|
||||
return &impure->vlu_desc;
|
||||
}
|
||||
|
||||
case nod_get_bookmark:
|
||||
{
|
||||
Bookmark* bookmark =
|
||||
RSE_get_bookmark(tdbb, *(RecordSource**) node->nod_arg[e_getmark_rsb]);
|
||||
return &bookmark->bkm_desc;
|
||||
}
|
||||
|
||||
case nod_bookmark:
|
||||
{
|
||||
Bookmark* bookmark = BKM_lookup(node->nod_arg[e_bookmark_id]);
|
||||
return &bookmark->bkm_key_desc;
|
||||
}
|
||||
|
||||
case nod_cardinality:
|
||||
impure->vlu_misc.vlu_long =
|
||||
(*(RecordSource**) node->nod_arg[e_card_rsb])->rsb_cardinality;
|
||||
impure->vlu_desc.dsc_dtype = dtype_long;
|
||||
impure->vlu_desc.dsc_length = sizeof(ULONG);
|
||||
impure->vlu_desc.dsc_scale = 0;
|
||||
impure->vlu_desc.dsc_sub_type = 0;
|
||||
impure->vlu_desc.dsc_address = (UCHAR *) & impure->vlu_misc.vlu_long;
|
||||
return &impure->vlu_desc;
|
||||
#endif
|
||||
default: /* Shut up some compiler warnings */
|
||||
break;
|
||||
}
|
||||
@ -3511,144 +3458,6 @@ static void init_agg_distinct(thread_db* tdbb, const jrd_nod* node)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static dsc* lock_record(thread_db* tdbb, jrd_nod* node, impure_value* impure)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* l o c k _ r e c o r d
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Lock a record and return a descriptor
|
||||
* pointing to the lock handle.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
|
||||
DEV_BLKCHK(node, type_nod);
|
||||
|
||||
/* Initialize descriptor */
|
||||
|
||||
impure->vlu_desc.dsc_address = (UCHAR *) & impure->vlu_misc.vlu_long;
|
||||
impure->vlu_desc.dsc_dtype = dtype_long;
|
||||
impure->vlu_desc.dsc_length = sizeof(ULONG);
|
||||
impure->vlu_desc.dsc_scale = 0;
|
||||
|
||||
/* get the locking level */
|
||||
|
||||
dsc* desc = EVL_expr(tdbb, node->nod_arg[e_lockrec_level]);
|
||||
const USHORT lock_level = (USHORT) MOV_get_long(desc, 0);
|
||||
if (lock_level > LCK_EX)
|
||||
ERR_post(isc_bad_lock_level, isc_arg_number, (SLONG) lock_level, 0);
|
||||
|
||||
/* perform the actual lock (or unlock) */
|
||||
|
||||
RecordSource* rsb = *(RecordSource**) node->nod_arg[e_lockrec_rsb];
|
||||
record_param* rpb = request->req_rpb + rsb->rsb_stream;
|
||||
Lock* lock = NULL;
|
||||
if (!lock_level)
|
||||
RLCK_unlock_record(0, rpb);
|
||||
else if (!(lock = RLCK_lock_record(rpb, lock_level, 0, 0)))
|
||||
ERR_warning(isc_record_lock, 0);
|
||||
|
||||
/* return the lock handle (actually the pointer to the lock block) */
|
||||
|
||||
#if SIZEOF_VOID_P != 8
|
||||
impure->vlu_misc.vlu_long = (ULONG) lock;
|
||||
#else
|
||||
{
|
||||
/* The lock pointer can't be stored in a ULONG. Therefore we must
|
||||
generate a ULONG value that can be used to retrieve the pointer.
|
||||
Basically we will keep a vector of user locks and give the user
|
||||
an index into this vector. When the user releases a lock, its
|
||||
slot in the vector is zeroed and it becomes available for reuse. */
|
||||
|
||||
Attachment* att = tdbb->tdbb_attachment;
|
||||
const ULONG slot = ALL_get_free_object(tdbb->tdbb_database->dbb_permanent,
|
||||
&att->att_lck_quick_ref, 50);
|
||||
(*att->att_lck_quick_ref)[slot] = lock;
|
||||
impure->vlu_misc.vlu_long = slot;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &impure->vlu_desc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static dsc* lock_relation(thread_db* tdbb, jrd_nod* node, impure_value* impure)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* l o c k _ r e l a t i o n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Lock a relation and return a descriptor
|
||||
* pointing to the lock handle.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
DEV_BLKCHK(node, type_nod);
|
||||
|
||||
/* Initialize descriptor */
|
||||
|
||||
impure->vlu_desc.dsc_address = (UCHAR *) & impure->vlu_misc.vlu_long;
|
||||
impure->vlu_desc.dsc_dtype = dtype_long;
|
||||
impure->vlu_desc.dsc_length = sizeof(ULONG);
|
||||
impure->vlu_desc.dsc_scale = 0;
|
||||
|
||||
/* get the locking level */
|
||||
|
||||
dsc* desc = EVL_expr(tdbb, node->nod_arg[e_lockrel_level]);
|
||||
const USHORT lock_level = (USHORT) MOV_get_long(desc, 0);
|
||||
if (lock_level > LCK_EX)
|
||||
ERR_post(isc_bad_lock_level, isc_arg_number, (SLONG) lock_level, 0);
|
||||
|
||||
/* perform the actual lock (or unlock) */
|
||||
|
||||
jrd_nod* relation_node = node->nod_arg[e_lockrel_relation];
|
||||
jrd_rel* relation = (jrd_rel*) relation_node->nod_arg[e_rel_relation];
|
||||
Lock* lock = NULL;
|
||||
if (!lock_level)
|
||||
RLCK_unlock_relation(0, relation);
|
||||
else
|
||||
lock = RLCK_lock_relation(relation, lock_level, 0, relation);
|
||||
|
||||
/* return the lock handle (actually the pointer to the lock block) */
|
||||
|
||||
#if SIZEOF_VOID_P != 8
|
||||
impure->vlu_misc.vlu_long = (ULONG) lock;
|
||||
#else
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
/* The lock pointer can't be stored in a ULONG. Therefore we must
|
||||
generate a ULONG value that can be used to retrieve the pointer.
|
||||
Basically we will keep a vector of user locks and give the user
|
||||
an index into this vector. When the user releases a lock, its
|
||||
slot in the vector is zeroed and it becomes available for reuse. */
|
||||
|
||||
Attachment* att = tdbb->tdbb_attachment;
|
||||
const ULONG slot =
|
||||
ALL_get_free_object(tdbb->tdbb_database->dbb_permanent,
|
||||
&att->att_lck_quick_ref, 50);
|
||||
(*att->att_lck_quick_ref)[slot] = lock;
|
||||
impure->vlu_misc.vlu_long = slot;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &impure->vlu_desc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static dsc* lock_state(thread_db* tdbb, jrd_nod* node, impure_value* impure)
|
||||
{
|
||||
/**************************************
|
||||
|
654
src/jrd/exe.cpp
654
src/jrd/exe.cpp
@ -216,15 +216,6 @@ inline void PreModifyEraseTriggers(thread_db*, trig_vec**, SSHORT, record_param*
|
||||
Record*, jrd_req::req_ta);
|
||||
static void stuff_stack_trace(const jrd_req*);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static jrd_nod* find(thread_db*, jrd_nod*);
|
||||
static jrd_nod* find_dbkey(thread_db*, jrd_nod*);
|
||||
static Lock* implicit_record_lock(jrd_tra*, record_param*);
|
||||
static jrd_nod* release_bookmark(thread_db*, jrd_nod*);
|
||||
static jrd_nod* set_bookmark(thread_db*, jrd_nod*);
|
||||
static jrd_nod* set_index(thread_db*, jrd_nod*);
|
||||
static jrd_nod* stream(thread_db*, jrd_nod*);
|
||||
#endif
|
||||
|
||||
/* macro definitions */
|
||||
|
||||
@ -255,26 +246,6 @@ const size_t MAX_STACK_TRACE = 2048;
|
||||
|
||||
const int RECORD_LOCK_CHECK_INTERVAL = 10;
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
// TMN: RAII class for Lock. Unlocks the Lock on destruction.
|
||||
class LCK_RAII_wrapper
|
||||
{
|
||||
LCK_RAII_wrapper() : l(0) {}
|
||||
~LCK_RAII_wrapper() {
|
||||
if (l) {
|
||||
RLCK_unlock_record_implicit(l, 0);
|
||||
}
|
||||
}
|
||||
void assign(Lock* lock) { l = lock; }
|
||||
|
||||
Lock* l;
|
||||
|
||||
private:
|
||||
LCK_RAII_wrapper(const LCK_RAII_wrapper&); // no impl.
|
||||
void operator=(const LCK_RAII_wrapper&); // no impl.
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
void EXE_assignment(thread_db* tdbb, jrd_nod* node)
|
||||
{
|
||||
@ -499,38 +470,6 @@ void EXE_assignment(thread_db* tdbb, jrd_nod* node)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool EXE_crack(thread_db* tdbb, RecordSource* rsb, USHORT flags)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* E X E _ c r a c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Check whether stream is on a crack, BOF
|
||||
* or EOF, according to the flags passed.
|
||||
*
|
||||
**************************************/
|
||||
DEV_BLKCHK(rsb, type_rsb);
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
|
||||
/* correct boolean rsbs to point to the "real" rsb */
|
||||
|
||||
if (rsb->rsb_type == rsb_boolean)
|
||||
rsb = rsb->rsb_next;
|
||||
irsb* impure = (IRSB) ((UCHAR *) request + rsb->rsb_impure);
|
||||
|
||||
/* if any of the passed flags are set, return true */
|
||||
|
||||
return (impure->irsb_flags & flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
jrd_req* EXE_find_request(thread_db* tdbb, jrd_req* request, bool validate)
|
||||
{
|
||||
/**************************************
|
||||
@ -602,42 +541,6 @@ jrd_req* EXE_find_request(thread_db* tdbb, jrd_req* request, bool validate)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void EXE_mark_crack(thread_db* tdbb, RecordSource* rsb, USHORT flag)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* E X E _ m a r k _ c r a c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Mark a stream as being at a crack,
|
||||
* plus report the fact in the status
|
||||
* vector.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
DEV_BLKCHK(rsb, type_rsb);
|
||||
|
||||
/* correct boolean rsbs to point to the "real" rsb */
|
||||
|
||||
if (rsb->rsb_type == rsb_boolean)
|
||||
rsb = rsb->rsb_next;
|
||||
|
||||
RSE_MARK_CRACK(tdbb, rsb, flag);
|
||||
|
||||
if (flag == irsb_eof)
|
||||
ERR_warning(isc_stream_eof, 0);
|
||||
else if (flag == irsb_bof)
|
||||
ERR_warning(isc_stream_bof, 0);
|
||||
else if (flag & irsb_crack)
|
||||
ERR_warning(isc_stream_crack, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void EXE_receive(thread_db* tdbb,
|
||||
jrd_req* request,
|
||||
USHORT msg,
|
||||
@ -1203,16 +1106,6 @@ static jrd_nod* erase(thread_db* tdbb, jrd_nod* node, SSHORT which_trig)
|
||||
ERR_post(isc_no_cur_rec, 0);
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
/* for navigational streams, retrieve the rsb */
|
||||
RecordSource* rsb = NULL;
|
||||
irsb* impure = NULL;
|
||||
if (node->nod_arg[e_erase_rsb]) {
|
||||
rsb = *(RecordSource**) node->nod_arg[e_erase_rsb];
|
||||
impure = (IRSB) ((UCHAR *) request + rsb->rsb_impure);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (request->req_operation) {
|
||||
case jrd_req::req_evaluate:
|
||||
{
|
||||
@ -1234,17 +1127,6 @@ static jrd_nod* erase(thread_db* tdbb, jrd_nod* node, SSHORT which_trig)
|
||||
return node->nod_parent;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
/* if we are on a crack in a navigational stream, erase
|
||||
is not a valid operation */
|
||||
|
||||
if (rsb && EXE_crack(tdbb, rsb, irsb_bof | irsb_eof | irsb_crack)) {
|
||||
EXE_mark_crack(tdbb, rsb, impure->irsb_flags);
|
||||
request->req_operation = jrd_req::req_return;
|
||||
return node->nod_parent;
|
||||
}
|
||||
#endif
|
||||
|
||||
request->req_operation = jrd_req::req_return;
|
||||
RLCK_reserve_relation(tdbb, transaction, relation, true, true);
|
||||
|
||||
@ -1257,30 +1139,6 @@ static jrd_nod* erase(thread_db* tdbb, jrd_nod* node, SSHORT which_trig)
|
||||
rpb->rpb_stream_flags &= ~RPB_s_refetch;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
/* set up to do record locking; in case of a consistency
|
||||
mode transaction, we already have an exclusive lock on
|
||||
the table, so don't bother */
|
||||
|
||||
LCK_RAII_wrapper implicit_lock;
|
||||
|
||||
if (!(transaction->tra_flags & TRA_degree3))
|
||||
{
|
||||
/* check whether record locking is turned on */
|
||||
|
||||
Lock* record_locking = RLCK_record_locking(relation);
|
||||
if (record_locking->lck_physical != LCK_PR)
|
||||
{
|
||||
/* get an implicit lock on the record */
|
||||
|
||||
implicit_lock.assign(implicit_record_lock(transaction, rpb));
|
||||
|
||||
/* set up to catch any errors so that we can
|
||||
release the implicit lock */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (transaction != dbb->dbb_sys_trans)
|
||||
++transaction->tra_save_point->sav_verb_count;
|
||||
|
||||
@ -1347,15 +1205,6 @@ static jrd_nod* erase(thread_db* tdbb, jrd_nod* node, SSHORT which_trig)
|
||||
--transaction->tra_save_point->sav_verb_count;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
|
||||
/* if the stream is navigational, it is now positioned on a crack */
|
||||
|
||||
if (rsb) {
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
}
|
||||
#endif
|
||||
|
||||
return node->nod_parent;
|
||||
}
|
||||
|
||||
@ -1657,172 +1506,6 @@ static jrd_req* execute_triggers(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static jrd_nod* find(thread_db* tdbb, jrd_nod* node)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* f i n d
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Find the given key value in a stream.
|
||||
* Assume that the stream is open.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
BLKCHK(node, type_nod);
|
||||
|
||||
if (request->req_operation == jrd_req::req_evaluate)
|
||||
{
|
||||
RecordSource* rsb = *((RecordSource**) node->nod_arg[e_find_rsb]);
|
||||
|
||||
const dsc* desc = EVL_expr(tdbb, node->nod_arg[e_find_operator]);
|
||||
|
||||
const USHORT blr_operator = (desc && !(request->req_flags & req_null)) ?
|
||||
(USHORT) MOV_get_long(desc, 0) : MAX_USHORT;
|
||||
|
||||
if (blr_operator != blr_equiv &&
|
||||
blr_operator != blr_eql &&
|
||||
blr_operator != blr_leq &&
|
||||
blr_operator != blr_lss &&
|
||||
blr_operator != blr_geq &&
|
||||
blr_operator != blr_gtr)
|
||||
{
|
||||
ERR_post(isc_invalid_operator, 0);
|
||||
}
|
||||
|
||||
desc = EVL_expr(tdbb, node->nod_arg[e_find_direction]);
|
||||
|
||||
const USHORT direction = (desc && !(request->req_flags & req_null)) ?
|
||||
(USHORT) MOV_get_long(desc, 0) : MAX_USHORT;
|
||||
|
||||
if (direction != blr_backward &&
|
||||
direction != blr_forward &&
|
||||
direction != blr_backward_starting &&
|
||||
direction != blr_forward_starting)
|
||||
{
|
||||
ERR_post(isc_invalid_direction, 0);
|
||||
}
|
||||
|
||||
/* try to find the record; the position is defined to be on a crack
|
||||
regardless of whether we are at BOF or EOF; also be sure to perpetuate
|
||||
the forced crack (bug #7024) */
|
||||
|
||||
if (!RSE_find_record(tdbb, rsb, blr_operator, direction,
|
||||
node->nod_arg[e_find_args]))
|
||||
{
|
||||
if (EXE_crack(tdbb, rsb, irsb_bof | irsb_eof | irsb_crack))
|
||||
{
|
||||
if (EXE_crack(tdbb, rsb, irsb_forced_crack)) {
|
||||
EXE_mark_crack(tdbb, rsb, irsb_crack | irsb_forced_crack);
|
||||
}
|
||||
else if (EXE_crack(tdbb, rsb, irsb_bof)) {
|
||||
EXE_mark_crack(tdbb, rsb, irsb_bof);
|
||||
}
|
||||
else if (EXE_crack(tdbb, rsb, irsb_eof)) {
|
||||
EXE_mark_crack(tdbb, rsb, irsb_eof);
|
||||
}
|
||||
else {
|
||||
EXE_mark_crack(tdbb, rsb, irsb_crack);
|
||||
}
|
||||
}
|
||||
}
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
|
||||
return node->nod_parent;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static jrd_nod* find_dbkey(thread_db* tdbb, jrd_nod* node)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* f i n d _ d b k e y
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Find the given dbkey in a navigational stream,
|
||||
* resetting the position of the stream to that record.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
BLKCHK(node, type_nod);
|
||||
|
||||
if (request->req_operation == jrd_req::req_evaluate)
|
||||
{
|
||||
RecordSource* rsb = *((RecordSource**) node->nod_arg[e_find_dbkey_rsb]);
|
||||
|
||||
if (!RSE_find_dbkey(tdbb,
|
||||
rsb,
|
||||
node->nod_arg[e_find_dbkey_dbkey],
|
||||
node->nod_arg[e_find_dbkey_version]))
|
||||
{
|
||||
EXE_mark_crack(tdbb, rsb, irsb_crack);
|
||||
}
|
||||
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
|
||||
return node->nod_parent;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static Lock* implicit_record_lock(jrd_tra* transaction, record_param* rpb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* i m p l i c i t _ r e c o r d _ l o c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* An update to a record is being attempted and
|
||||
* record locking has been initiated. Take out
|
||||
* an implicit record lock to prevent updating
|
||||
* a record that someone has explicitly locked.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
|
||||
DEV_BLKCHK(transaction, type_tra);
|
||||
|
||||
jrd_rel* relation = rpb->rpb_relation;
|
||||
Lock* record_locking = relation->rel_record_locking;
|
||||
|
||||
/* occasionally we should check whether we really still need to
|
||||
do record locking; this is defined as RECORD_LOCK_CHECK_INTERVAL--
|
||||
if we can get a PR on the record locking lock there is no need
|
||||
to do implicit locking anymore */
|
||||
|
||||
if ((record_locking->lck_physical == LCK_none) &&
|
||||
!(relation->rel_lock_total % RECORD_LOCK_CHECK_INTERVAL) &&
|
||||
LCK_lock_non_blocking(tdbb, record_locking, LCK_PR, LCK_NO_WAIT))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Lock* lock = RLCK_lock_record_implicit(transaction, rpb, LCK_SW, 0, 0);
|
||||
if (!lock) {
|
||||
ERR_post(isc_record_lock, 0);
|
||||
}
|
||||
|
||||
return lock;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void stuff_stack_trace(const jrd_req* request)
|
||||
{
|
||||
Firebird::string sTrace;
|
||||
@ -2717,107 +2400,6 @@ static jrd_nod* looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node)
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
case nod_stream:
|
||||
node = stream(tdbb, node);
|
||||
break;
|
||||
|
||||
case nod_find:
|
||||
node = find(tdbb, node);
|
||||
break;
|
||||
|
||||
case nod_find_dbkey:
|
||||
case nod_find_dbkey_version:
|
||||
node = find_dbkey(tdbb, node);
|
||||
break;
|
||||
|
||||
case nod_set_index:
|
||||
node = set_index(tdbb, node);
|
||||
break;
|
||||
|
||||
case nod_set_bookmark:
|
||||
node = set_bookmark(tdbb, node);
|
||||
break;
|
||||
|
||||
case nod_release_bookmark:
|
||||
node = release_bookmark(tdbb, node);
|
||||
break;
|
||||
|
||||
case nod_end_range:
|
||||
node = RNG_end(node);
|
||||
break;
|
||||
|
||||
case nod_delete_range:
|
||||
node = RNG_delete(node);
|
||||
break;
|
||||
|
||||
case nod_delete_ranges:
|
||||
if (request->req_operation == jrd_req::req_evaluate) {
|
||||
RNG_delete_ranges(request);
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
node = node->nod_parent;
|
||||
break;
|
||||
|
||||
case nod_range_relation:
|
||||
node = RNG_add_relation(node);
|
||||
break;
|
||||
|
||||
case nod_release_lock:
|
||||
if (request->req_operation == jrd_req::req_evaluate) {
|
||||
DSC *desc;
|
||||
|
||||
desc = EVL_expr(tdbb, node->nod_arg[e_rellock_lock]);
|
||||
#if SIZEOF_VOID_P != 8
|
||||
RLCK_release_lock(*(Lock**) desc->dsc_address);
|
||||
#else
|
||||
{
|
||||
Attachment* attachment = tdbb->tdbb_attachment;
|
||||
|
||||
Lock* lock = NULL;
|
||||
const ULONG slot = *(ULONG *) desc->dsc_address;
|
||||
vec<Lock*>* vector = attachment->att_lck_quick_ref;
|
||||
if (vector && slot < vector->count()) {
|
||||
lock = (*vector)[slot];
|
||||
}
|
||||
RLCK_release_lock(lock);
|
||||
(*vector)[slot] = NULL;
|
||||
}
|
||||
#endif
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
node = node->nod_parent;
|
||||
break;
|
||||
|
||||
case nod_release_locks:
|
||||
if (request->req_operation == jrd_req::req_evaluate) {
|
||||
RLCK_release_locks(request->req_attachment);
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
node = node->nod_parent;
|
||||
break;
|
||||
|
||||
case nod_force_crack:
|
||||
if (request->req_operation == jrd_req::req_evaluate) {
|
||||
RSE_MARK_CRACK(tdbb, *(RecordSource**) node->nod_arg[1],
|
||||
irsb_crack | irsb_forced_crack);
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
node = node->nod_parent;
|
||||
break;
|
||||
|
||||
case nod_reset_stream:
|
||||
if (request->req_operation == jrd_req::req_evaluate) {
|
||||
RSE_reset_position(tdbb,
|
||||
*(RecordSource**) node->nod_arg[e_reset_from_rsb],
|
||||
request->req_rpb +
|
||||
(USHORT)(ULONG) node->nod_arg[e_reset_to_stream]);
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
node = node->nod_parent;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case nod_set_generator:
|
||||
if (request->req_operation == jrd_req::req_evaluate) {
|
||||
dsc* desc = EVL_expr(tdbb, node->nod_arg[e_gen_value]);
|
||||
@ -2981,25 +2563,6 @@ static jrd_nod* modify(thread_db* tdbb, jrd_nod* node, SSHORT which_trig)
|
||||
const SSHORT new_stream = (USHORT)(IPTR) node->nod_arg[e_mod_new_stream];
|
||||
record_param* new_rpb = &request->req_rpb[new_stream];
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
/* for navigational streams, retrieve the rsb */
|
||||
RecordSource* rsb = NULL;
|
||||
IRSB irsb;
|
||||
|
||||
if (node->nod_arg[e_mod_rsb]) {
|
||||
rsb = *(RecordSource**) node->nod_arg[e_mod_rsb];
|
||||
irsb = (IRSB) ((UCHAR *) request + rsb->rsb_impure);
|
||||
}
|
||||
|
||||
/* if we are on a crack in a navigational stream, modify is an illegal operation */
|
||||
|
||||
if (rsb && EXE_crack(tdbb, rsb, irsb_bof | irsb_eof | irsb_crack)) {
|
||||
EXE_mark_crack(tdbb, rsb, irsb->irsb_flags);
|
||||
request->req_operation = jrd_req::req_return;
|
||||
return node->nod_parent;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the stream was sorted, the various fields in the rpb are
|
||||
probably junk. Just to make sure that everything is cool,
|
||||
refetch and release the record. */
|
||||
@ -3029,24 +2592,6 @@ static jrd_nod* modify(thread_db* tdbb, jrd_nod* node, SSHORT which_trig)
|
||||
varchar field whose tail may contain garbage. */
|
||||
cleanup_rpb(tdbb, new_rpb);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
/* check to see if record locking has been initiated in this database;
|
||||
if so then lock the record for shared write so that normal processing
|
||||
will be able to read or write the record but not when an explicit
|
||||
lock has been taken out */
|
||||
|
||||
LCK_RAII_wrapper implicit_lock;
|
||||
|
||||
if (!(transaction->tra_flags & TRA_degree3))
|
||||
{
|
||||
const Lock* record_locking = RLCK_record_locking(relation);
|
||||
if (record_locking->lck_physical != LCK_PR)
|
||||
{
|
||||
implicit_lock.assign(implicit_record_lock(transaction, org_rpb));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (transaction != dbb->dbb_sys_trans)
|
||||
++transaction->tra_save_point->sav_verb_count;
|
||||
|
||||
@ -3113,17 +2658,6 @@ static jrd_nod* modify(thread_db* tdbb, jrd_nod* node, SSHORT which_trig)
|
||||
--transaction->tra_save_point->sav_verb_count;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
|
||||
/* if the stream is navigational, we must position the stream on the new
|
||||
record version, but first set the record number */
|
||||
|
||||
new_rpb->rpb_number = org_rpb->rpb_number;
|
||||
if (rsb) {
|
||||
RSE_reset_position(tdbb, rsb, new_rpb);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* CVC: Increment the counter only if we called VIO/EXT_modify() and
|
||||
we were successful. */
|
||||
if (!(request->req_view_flags & req_first_modify_return)) {
|
||||
@ -3323,33 +2857,6 @@ static void release_blobs(thread_db* tdbb, jrd_req* request)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static jrd_nod* release_bookmark(thread_db* tdbb, jrd_nod* node)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* r e l e a s e _ b o o k m a r k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Deallocate the passed bookmark.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
BLKCHK(node, type_nod);
|
||||
|
||||
if (request->req_operation == jrd_req::req_evaluate) {
|
||||
BKM_release(node->nod_arg[e_relmark_id]);
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
|
||||
return node->nod_parent;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void release_proc_save_points(jrd_req* request)
|
||||
{
|
||||
/**************************************
|
||||
@ -3510,12 +3017,7 @@ static void seek_rsb(
|
||||
switch (direction) {
|
||||
case blr_forward: /* go forward from the current location */
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
if ((offset == 1) && request->req_begin_ranges)
|
||||
impure->irsb_flags |= irsb_refresh;
|
||||
#endif
|
||||
|
||||
/* the rsb_backwards flag is used to indicate the direction to seek in;
|
||||
/* the rsb_backwards flag is used to indicate the direction to seek in;
|
||||
this is sticky in the sense that after the user has seek'ed in the
|
||||
backward direction, the next retrieval from a blr_for loop will also
|
||||
be in the backward direction--this allows us to continue scrolling
|
||||
@ -3532,11 +3034,6 @@ static void seek_rsb(
|
||||
|
||||
case blr_backward: /* go backward from the current location */
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
if ((offset == 1) && request->req_begin_ranges)
|
||||
impure->irsb_flags |= irsb_refresh;
|
||||
#endif
|
||||
|
||||
impure->irsb_flags |= irsb_last_backwards;
|
||||
|
||||
while (offset) {
|
||||
@ -3587,10 +3084,6 @@ static void seek_rsb(
|
||||
// check above, but anyway...
|
||||
BUGCHECK(232);
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
impure->irsb_flags &= ~irsb_refresh;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -3668,59 +3161,6 @@ static jrd_nod* send_msg(thread_db* tdbb, jrd_nod* node)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static jrd_nod* set_bookmark(thread_db* tdbb, jrd_nod* node)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* s e t _ b o o k m a r k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Set a stream to the location of the
|
||||
* specified bookmark.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
BLKCHK(node, type_nod);
|
||||
|
||||
if (request->req_operation == jrd_req::req_evaluate) {
|
||||
Bookmark* bookmark = BKM_lookup(node->nod_arg[e_setmark_id]);
|
||||
const USHORT stream = (USHORT)(ULONG) node->nod_arg[e_setmark_stream];
|
||||
record_param* rpb = &request->req_rpb[stream];
|
||||
RecordSource* rsb = *((RecordSource**) node->nod_arg[e_setmark_rsb]);
|
||||
irsb* impure = (IRSB) ((UCHAR *) request + rsb->rsb_impure);
|
||||
|
||||
/* check if the bookmark was at beginning or end of file
|
||||
and flag the rsb accordingly */
|
||||
|
||||
RSE_MARK_CRACK(tdbb, rsb, 0);
|
||||
if (bookmark->bkm_flags & bkm_bof)
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_bof);
|
||||
else if (bookmark->bkm_flags & bkm_eof)
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_eof);
|
||||
else if (bookmark->bkm_flags & bkm_crack) {
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
if (bookmark->bkm_flags & bkm_forced_crack)
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_forced_crack);
|
||||
}
|
||||
|
||||
if (!RSE_set_bookmark(tdbb, rsb, rpb, bookmark)) {
|
||||
EXE_mark_crack(tdbb, rsb,
|
||||
impure->irsb_flags & (irsb_crack | irsb_eof |
|
||||
irsb_bof));
|
||||
}
|
||||
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
|
||||
return node->nod_parent;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void set_error(thread_db* tdbb, const xcp_repeat* exception, jrd_nod* msg_node)
|
||||
{
|
||||
/**************************************
|
||||
@ -3837,58 +3277,6 @@ static void set_error(thread_db* tdbb, const xcp_repeat* exception, jrd_nod* msg
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static jrd_nod* set_index(thread_db* tdbb, jrd_nod* node)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* s e t _ i n d e x
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Execute a SET INDEX statement.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
BLKCHK(node, type_nod);
|
||||
|
||||
if (request->req_operation == jrd_req::req_evaluate) {
|
||||
const USHORT stream = (USHORT)(ULONG) node->nod_arg[e_index_stream];
|
||||
|
||||
record_param* rpb = &request->req_rpb[stream];
|
||||
jrd_rel* relation = rpb->rpb_relation;
|
||||
|
||||
/* if id is non-zero, get the index definition;
|
||||
otherwise it indicates revert to natural order */
|
||||
|
||||
const dsc* desc = EVL_expr(tdbb, node->nod_arg[e_index_index]);
|
||||
const USHORT id = (desc && !(request->req_flags & req_null)) ?
|
||||
MOV_get_long(desc, 0) : 0;
|
||||
|
||||
index_desc idx;
|
||||
if (id && BTR_lookup(tdbb, relation, id - 1, &idx))
|
||||
{
|
||||
ERR_post(isc_indexnotdefined, isc_arg_string, relation->rel_name,
|
||||
isc_arg_number, (SLONG) id, 0);
|
||||
}
|
||||
|
||||
/* generate a new rsb in place of the old */
|
||||
|
||||
RSE_close(tdbb, *(RecordSource**) node->nod_arg[e_index_rsb]);
|
||||
OPT_set_index(tdbb, request, (RecordSource**) node->nod_arg[e_index_rsb],
|
||||
relation, id ? &idx : NULL);
|
||||
RSE_open(tdbb, *(RecordSource**) node->nod_arg[e_index_rsb]);
|
||||
|
||||
request->req_operation = jrd_req::req_return;
|
||||
}
|
||||
|
||||
return node->nod_parent;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static jrd_nod* stall(thread_db* tdbb, jrd_nod* node)
|
||||
{
|
||||
/**************************************
|
||||
@ -4092,45 +3480,7 @@ static jrd_nod* store(thread_db* tdbb, jrd_nod* node, SSHORT which_trig)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static jrd_nod* stream(thread_db* tdbb, jrd_nod* node)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* s t r e a m
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Execute a STREAM statement.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
BLKCHK(node, type_nod);
|
||||
|
||||
RecordSource* rsb = ((RecordSelExpr*) node)->rse_rsb;
|
||||
|
||||
switch (request->req_operation) {
|
||||
case jrd_req::req_evaluate:
|
||||
RSE_open(tdbb, rsb);
|
||||
request->req_operation = jrd_req::req_return;
|
||||
|
||||
case jrd_req::req_return:
|
||||
node = node->nod_parent;
|
||||
break;
|
||||
|
||||
default:
|
||||
RSE_close(tdbb, rsb);
|
||||
node = node->nod_parent;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static bool test_and_fixup_error(thread_db* tdbb, const PsqlException* conditions,
|
||||
static bool test_and_fixup_error(thread_db* tdbb, const PsqlException* conditions,
|
||||
jrd_req* request)
|
||||
{
|
||||
/**************************************
|
||||
|
@ -40,11 +40,5 @@ void EXE_unwind(Jrd::thread_db*, Jrd::jrd_req*);
|
||||
void EXE_seek(Jrd::thread_db*, Jrd::jrd_req*, USHORT, ULONG);
|
||||
#endif
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool EXE_crack(Jrd::thread_db*, Jrd::RecordSource*, USHORT);
|
||||
void EXE_mark_crack(Jrd::thread_db*, Jrd::RecordSource*, USHORT);
|
||||
#endif
|
||||
|
||||
|
||||
#endif // JRD_EXE_PROTO_H
|
||||
|
||||
|
@ -2222,9 +2222,6 @@ ISC_STATUS GDS_DDL(ISC_STATUS* user_status,
|
||||
* a rollback_retain (). This will backout the
|
||||
* effects of the transaction, mark it dead and
|
||||
* start a new transaction.
|
||||
|
||||
* For now only ExpressLink will use this feature. Later
|
||||
* a new entry point may be added.
|
||||
*/
|
||||
|
||||
if (transaction->tra_flags & TRA_perform_autocommit)
|
||||
@ -5726,32 +5723,6 @@ static void release_attachment(Attachment* attachment)
|
||||
attachment->att_val_errors = NULL;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
// Release the persistent locks taken out during the attachment
|
||||
vec<Lock*>* lock_vector = attachment->att_relation_locks;
|
||||
if (lock_vector)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (vec<Lock*>::iterator lock = lock_vector->begin();
|
||||
i < lock_vector->count(); i++, lock++)
|
||||
{
|
||||
if (*lock)
|
||||
{
|
||||
LCK_release(tdbb, *lock);
|
||||
delete *lock;
|
||||
}
|
||||
}
|
||||
delete lock_vector;
|
||||
}
|
||||
|
||||
Lock* record_lock;
|
||||
for (record_lock = attachment->att_record_locks; record_lock;
|
||||
record_lock = record_lock->lck_att_next)
|
||||
{
|
||||
LCK_release(tdbb, record_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* bug #7781, need to null out the attachment pointer of all locks which
|
||||
were hung off this attachment block, to ensure that the attachment
|
||||
block doesn't get dereferenced after it is released */
|
||||
@ -6564,22 +6535,6 @@ static void purge_attachment(thread_db* tdbb,
|
||||
delete user;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
Bookmark* bookmark;
|
||||
while ( (bookmark = attachment->att_bookmarks) ) {
|
||||
attachment->att_bookmarks = bookmark->bkm_next;
|
||||
delete bookmark;
|
||||
}
|
||||
|
||||
if (attachment->att_bkm_quick_ref) {
|
||||
delete attachment->att_bkm_quick_ref;
|
||||
}
|
||||
|
||||
if (attachment->att_lck_quick_ref) {
|
||||
delete attachment->att_lck_quick_ref;
|
||||
}
|
||||
#endif
|
||||
|
||||
delete attachment;
|
||||
}
|
||||
else
|
||||
|
@ -462,13 +462,6 @@ public:
|
||||
att_event_session(0),
|
||||
att_security_class(0),
|
||||
att_security_classes(0),
|
||||
#ifdef PC_ENGINE
|
||||
att_relation_locks(0),
|
||||
att_bookmarks(0),
|
||||
att_record_locks(0),
|
||||
att_bkm_quick_ref(0),
|
||||
att_lck_quick_ref(0),
|
||||
#endif
|
||||
att_flags(0),
|
||||
att_charset(0),
|
||||
att_lc_messages(0),
|
||||
@ -495,13 +488,6 @@ public:
|
||||
SecurityClass* att_security_class; // security class for database
|
||||
SecurityClass* att_security_classes; // security classes
|
||||
vcl* att_counts[DBB_max_count];
|
||||
#ifdef PC_ENGINE
|
||||
vec<Lock*>* att_relation_locks; // explicit persistent locks for relations
|
||||
Bookmark* att_bookmarks; // list of bookmarks taken out using this attachment
|
||||
Lock* att_record_locks; // explicit or implicit record locks taken out during attachment
|
||||
vec<Bookmark*>* att_bkm_quick_ref; // correspondence table of bookmarks
|
||||
vec<Lock*>* att_lck_quick_ref; // correspondence table of locks
|
||||
#endif
|
||||
ULONG att_flags; // Flags describing the state of the attachment
|
||||
SSHORT att_charset; // user's charset specified in dpb
|
||||
Firebird::PathName att_lc_messages; // attachment's preference for message natural language
|
||||
@ -751,15 +737,6 @@ public:
|
||||
SSHORT rel_scan_count; /* concurrent sequential scan count */
|
||||
|
||||
Lock* rel_existence_lock; /* existence lock, if any */
|
||||
#ifdef PC_ENGINE
|
||||
Lock* rel_interest_lock; /* interest lock to ensure compatibility of relation and record locks */
|
||||
Lock* rel_record_locking; /* lock to start record locking on relation */
|
||||
ULONG rel_explicit_locks; /* count of records explicitly locked in relation */
|
||||
ULONG rel_read_locks; /* count of records read locked in relation (implicit or explicit) */
|
||||
ULONG rel_write_locks; /* count of records write locked in relation (implicit or explicit) */
|
||||
ULONG rel_lock_total; /* count of records locked since database first attached */
|
||||
#endif
|
||||
|
||||
Lock* rel_partners_lock; /* partners lock */
|
||||
IndexLock* rel_index_locks; /* index existence locks */
|
||||
IndexBlock* rel_index_blocks; /* index blocks for caching index info */
|
||||
|
697
src/jrd/nav.cpp
697
src/jrd/nav.cpp
@ -61,10 +61,6 @@ static int compare_keys(const index_desc*, const UCHAR*, USHORT,
|
||||
#ifdef SCROLLABLE_CURSORS
|
||||
static void expand_index(WIN *);
|
||||
#endif
|
||||
#ifdef PC_ENGINE
|
||||
static bool find_dbkey(RecordSource*, ULONG);
|
||||
static bool find_record(RecordSource*, RSE_GET_MODE, temporary_key*, USHORT, USHORT);
|
||||
#endif
|
||||
static btree_exp* find_current(exp_index_buf*, Ods::btree_page*, const UCHAR*);
|
||||
static bool find_saved_node(RecordSource*, IRSB_NAV, WIN *, UCHAR **);
|
||||
static UCHAR* get_position(thread_db*, RecordSource*, IRSB_NAV, WIN *, RSE_GET_MODE, btree_exp**);
|
||||
@ -150,318 +146,6 @@ exp_index_buf* NAV_expand_index(WIN * window, IRSB_NAV impure)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool NAV_find_record(RecordSource* rsb,
|
||||
USHORT blr_operator, USHORT direction, jrd_nod* find_key)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* N A V _ f i n d _ r e c o r d
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Find a record with the specified key value
|
||||
* in a stream opened on a navigational index.
|
||||
* This routine must set BOF, EOF, or CRACK.
|
||||
*
|
||||
**************************************/
|
||||
const bool backwards = (direction == blr_backward
|
||||
|| direction == blr_backward_starting);
|
||||
|
||||
USHORT search_flags;
|
||||
if (direction == blr_forward_starting || direction == blr_backward_starting)
|
||||
search_flags = irb_starting;
|
||||
else
|
||||
search_flags = 0;
|
||||
|
||||
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
irsb_nav* impure = (IRSB_NAV) ((UCHAR *) request + rsb->rsb_impure);
|
||||
WIN window(-1);
|
||||
|
||||
btree_nod* expanded_node;
|
||||
init_fetch(impure);
|
||||
if (!impure->irsb_nav_page) {
|
||||
nav_open(tdbb, rsb, impure, &window, RSE_get_forward, &expanded_node);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
}
|
||||
|
||||
// finding a record invalidates the visited records
|
||||
SBM_reset(&impure->irsb_nav_records_visited);
|
||||
|
||||
index_desc* idx =
|
||||
(index_desc*) ((SCHAR *) impure + (SLONG) rsb->rsb_arg[RSB_NAV_idx_offset]);
|
||||
|
||||
if ((idx == NULL) || (find_key->nod_count == 0) ||
|
||||
(find_key->nod_count > idx->idx_count))
|
||||
{
|
||||
ERR_post(gds__invalid_key, 0);
|
||||
}
|
||||
|
||||
if (find_key->nod_count < idx->idx_count)
|
||||
search_flags |= irb_partial;
|
||||
|
||||
temporary_key key_value;
|
||||
BTR_make_key(tdbb, find_key->nod_count, &find_key->nod_arg[0], idx,
|
||||
&key_value, (search_flags & irb_starting) != 0);
|
||||
|
||||
// save the key value
|
||||
impure->irsb_nav_length = key_value.key_length;
|
||||
MOVE_FAST(key_value.key_data, impure->irsb_nav_data,
|
||||
key_value.key_length);
|
||||
|
||||
// for descending indices, reverse the sense of the comparison operator
|
||||
// to simplify the following switch statement
|
||||
if (idx->idx_flags & idx_descending) {
|
||||
switch (blr_operator)
|
||||
{
|
||||
case blr_lss:
|
||||
blr_operator = blr_gtr;
|
||||
break;
|
||||
case blr_leq:
|
||||
blr_operator = blr_geq;
|
||||
break;
|
||||
case blr_gtr:
|
||||
blr_operator = blr_lss;
|
||||
break;
|
||||
case blr_geq:
|
||||
blr_operator = blr_leq;
|
||||
break;
|
||||
default: // silence compiler
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// find the proper record by comparing the passed key with the records in
|
||||
// the record stream, optimizing the fetch as best as possible by using the
|
||||
// index to get as close to the proper record as possible
|
||||
switch (blr_operator) {
|
||||
case blr_lss:
|
||||
if (backwards)
|
||||
// find the first record before the given key value
|
||||
{
|
||||
find_record(rsb, RSE_get_first, &key_value, find_key->nod_count,
|
||||
search_flags);
|
||||
return NAV_get_record(rsb, impure,
|
||||
request->req_rpb + rsb->rsb_stream,
|
||||
RSE_get_backward);
|
||||
}
|
||||
else
|
||||
// find the first record in the stream, assuming its key value is < the passed key
|
||||
{
|
||||
nav_open(tdbb, rsb, impure, &window, RSE_get_forward,
|
||||
&expanded_node);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
if (!NAV_get_record
|
||||
(rsb, impure, request->req_rpb + rsb->rsb_stream,
|
||||
RSE_get_forward))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (compare_keys
|
||||
(idx, impure->irsb_nav_data, impure->irsb_nav_length,
|
||||
&key_value, search_flags) < 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// break; unreachable
|
||||
|
||||
case blr_leq:
|
||||
if (backwards)
|
||||
// find the last record with the matching key; barring that, find the first less than
|
||||
{
|
||||
if (find_record
|
||||
(rsb, RSE_get_last, &key_value, find_key->nod_count,
|
||||
search_flags))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return NAV_get_record(rsb, impure,
|
||||
request->req_rpb + rsb->rsb_stream,
|
||||
RSE_get_backward);
|
||||
}
|
||||
else
|
||||
// find the first record in the stream, assuming its key value is <= the passed key
|
||||
{
|
||||
nav_open(tdbb, rsb, impure, &window, RSE_get_forward,
|
||||
&expanded_node);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
if (!NAV_get_record
|
||||
(rsb, impure, request->req_rpb + rsb->rsb_stream,
|
||||
RSE_get_forward))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (compare_keys
|
||||
(idx, impure->irsb_nav_data, impure->irsb_nav_length,
|
||||
&key_value, search_flags) <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// break; unreachable
|
||||
|
||||
case blr_equiv:
|
||||
case blr_eql:
|
||||
if (find_record(rsb, backwards ? RSE_get_last : RSE_get_first,
|
||||
&key_value, find_key->nod_count, search_flags))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// We need to override the crack semantics of find_record, because even
|
||||
// if we go to EOF or BOF as a result of the find, this is defined as a
|
||||
// crack. On the other hand, we do need to retain a forced crack if
|
||||
// one was set. bug #7024
|
||||
|
||||
if (impure->irsb_flags & irsb_forced_crack)
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack | irsb_forced_crack);
|
||||
else
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
// break; unreachable
|
||||
|
||||
case blr_gtr:
|
||||
if (backwards)
|
||||
// find the last record in the stream, assuming its key value is > the passed key
|
||||
{
|
||||
nav_open(tdbb, rsb, impure, &window, RSE_get_backward,
|
||||
&expanded_node);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
if (!NAV_get_record
|
||||
(rsb, impure, request->req_rpb + rsb->rsb_stream,
|
||||
RSE_get_backward))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (compare_keys
|
||||
(idx, impure->irsb_nav_data, impure->irsb_nav_length,
|
||||
&key_value, search_flags) > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
// find the first record after the last matching record
|
||||
{
|
||||
find_record(rsb, RSE_get_last, &key_value, find_key->nod_count,
|
||||
search_flags);
|
||||
|
||||
// special case when the key is greater than the last record in the file;
|
||||
// stream is defined to be on EOF; see bug #6151
|
||||
|
||||
if (impure->irsb_flags & irsb_eof)
|
||||
return false;
|
||||
|
||||
return NAV_get_record(rsb, impure,
|
||||
request->req_rpb + rsb->rsb_stream,
|
||||
RSE_get_forward);
|
||||
}
|
||||
// break; unreachable
|
||||
|
||||
case blr_geq:
|
||||
if (backwards)
|
||||
// find the last record in the stream, assuming its key value is >= the passed key
|
||||
{
|
||||
nav_open(tdbb, rsb, impure, &window, RSE_get_backward,
|
||||
&expanded_node);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
if (!NAV_get_record
|
||||
(rsb, impure, request->req_rpb + rsb->rsb_stream,
|
||||
RSE_get_backward))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (compare_keys
|
||||
(idx, impure->irsb_nav_data, impure->irsb_nav_length,
|
||||
&key_value, search_flags) >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
// find the first record of matching key; barring that, find the first greater
|
||||
{
|
||||
if (find_record
|
||||
(rsb, RSE_get_first, &key_value, find_key->nod_count,
|
||||
search_flags))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// special case when the key is greater than the last record in the file;
|
||||
// stream is defined to be on EOF; see bug #6151
|
||||
|
||||
if (impure->irsb_flags & irsb_eof)
|
||||
return false;
|
||||
|
||||
return NAV_get_record(rsb, impure,
|
||||
request->req_rpb + rsb->rsb_stream,
|
||||
RSE_get_forward);
|
||||
}
|
||||
// break; unreachable
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void NAV_get_bookmark(RecordSource* rsb, IRSB_NAV impure, Bookmark* bookmark)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* N A V _ g e t _ b o o k m a r k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Return a descriptor containing a pointer
|
||||
* to a bookmark data structure which describes
|
||||
* the current location of a navigational stream.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
// store the info necessary to return to this location in the index
|
||||
bookmark->bkm_number = impure->irsb_nav_number;
|
||||
bookmark->bkm_page = impure->irsb_nav_page;
|
||||
bookmark->bkm_incarnation = impure->irsb_nav_incarnation;
|
||||
bookmark->bkm_offset = impure->irsb_nav_offset;
|
||||
bookmark->bkm_expanded_offset = impure->irsb_nav_expanded_offset;
|
||||
|
||||
// store the current key value, setting up the key descriptor to point at it
|
||||
bookmark->bkm_key_desc.dsc_dtype = dtype_text;
|
||||
bookmark->bkm_key_desc.dsc_length = impure->irsb_nav_length;
|
||||
bookmark->bkm_key_desc.dsc_address = bookmark->bkm_key_data;
|
||||
MOVE_FAST(impure->irsb_nav_data, bookmark->bkm_key_data,
|
||||
impure->irsb_nav_length);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool NAV_get_record(thread_db* tdbb,
|
||||
RecordSource* rsb,
|
||||
IRSB_NAV impure, record_param* rpb, RSE_GET_MODE direction)
|
||||
@ -611,10 +295,6 @@ bool NAV_get_record(thread_db* tdbb,
|
||||
}
|
||||
|
||||
page = BTR_left_handoff(tdbb, &window, page, LCK_read);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
RNG_add_page(window.win_page);
|
||||
#endif
|
||||
expanded_page = NAV_expand_index(&window, 0);
|
||||
nextPointer = BTR_last_node(page, expanded_page, &expanded_next);
|
||||
|
||||
@ -637,9 +317,6 @@ bool NAV_get_record(thread_db* tdbb,
|
||||
page = (Ods::btree_page*) window.win_buffer;
|
||||
page = (Ods::btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling,
|
||||
LCK_read, pag_index);
|
||||
#ifdef PC_ENGINE
|
||||
RNG_add_page(window.win_page);
|
||||
#endif
|
||||
nextPointer = BTreeNode::getPointerFirstNode(page);
|
||||
exp_index_buf* expanded_page = window.win_expanded_buffer;
|
||||
if (expanded_page) {
|
||||
@ -769,31 +446,15 @@ bool NAV_get_record(thread_db* tdbb,
|
||||
|
||||
// reset the current navigational position in the index
|
||||
rpb->rpb_number = number;
|
||||
#ifdef PC_ENGINE
|
||||
if (direction != RSE_get_current)
|
||||
#endif
|
||||
set_position(impure, rpb, &window, pointer, expanded_node,
|
||||
key.key_data, key.key_length);
|
||||
set_position(impure, rpb, &window, pointer, expanded_node,
|
||||
key.key_data, key.key_length);
|
||||
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
|
||||
if (get_record(rsb, impure, rpb, &key, false)) {
|
||||
#ifdef PC_ENGINE
|
||||
if (impure->irsb_flags & irsb_refresh)
|
||||
RNG_add_record(rpb);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
// if we're here, we didn't find the record at the current position,
|
||||
// so it must have been deleted out from under us; by definition we
|
||||
// are on a crack (already marked by get_record())
|
||||
if (direction == RSE_get_current) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
nextPointer = get_position(tdbb, rsb, impure, &window, direction, &expanded_next);
|
||||
}
|
||||
|
||||
@ -804,106 +465,6 @@ bool NAV_get_record(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool NAV_reset_position(RecordSource* rsb, record_param* new_rpb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* N A V _ r e s e t _ p o s i t i o n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Reset the stream represented by the passed
|
||||
* rsb to the record indicated by the passed rpb.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
irsb_nav* impure = (IRSB_NAV) ((UCHAR *) request + rsb->rsb_impure);
|
||||
WIN window(-1);
|
||||
|
||||
btree_nod* expanded_node;
|
||||
init_fetch(impure);
|
||||
if (!impure->irsb_nav_page) {
|
||||
nav_open(tdbb, rsb, impure, &window, RSE_get_current, &expanded_node);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
}
|
||||
|
||||
// resetting the stream invalidates the visited records
|
||||
SBM_reset(&impure->irsb_nav_records_visited);
|
||||
|
||||
index_desc* idx = (index_desc*) ((SCHAR*) impure + (SLONG) rsb->rsb_arg[RSB_NAV_idx_offset]);
|
||||
|
||||
// save the record number, in case the passed new_rpb is
|
||||
// the same as the one on the rpb, in which case it will
|
||||
// be updated by find_record()--bug #7426
|
||||
|
||||
const RecordNumber record_number = new_rpb->rpb_number;
|
||||
|
||||
// find the key value of the new position, and set the stream to it
|
||||
temporary_key key_value;
|
||||
BTR_key(tdbb, new_rpb->rpb_relation, new_rpb->rpb_record, idx,
|
||||
&key_value, 0);
|
||||
if (!find_record(rsb, RSE_get_first, &key_value, idx->idx_count, 0)) // XXX
|
||||
return false;
|
||||
|
||||
// now find the dbkey of the new record within the
|
||||
// duplicates of this key value
|
||||
return find_dbkey(rsb, record_number);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool NAV_set_bookmark(RecordSource* rsb, IRSB_NAV impure, record_param* rpb, Bookmark* bookmark)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* N A V _ s e t _ b o o k m a r k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Set up the impure area so that the current
|
||||
* position of the stream is that of the
|
||||
* stored bookmark.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
// setting to bookmark invalidates the visited records
|
||||
SBM_reset(&impure->irsb_nav_records_visited);
|
||||
|
||||
// save the bookmark state in the impure area for the stream
|
||||
impure->irsb_nav_number = bookmark->bkm_number;
|
||||
impure->irsb_nav_incarnation = bookmark->bkm_incarnation;
|
||||
impure->irsb_nav_offset = bookmark->bkm_offset;
|
||||
impure->irsb_nav_expanded_offset = bookmark->bkm_expanded_offset;
|
||||
|
||||
// assuming we had already fetched a page when
|
||||
// we set the bookmark, make sure the "first" flag
|
||||
// is not set so that we don't reopen the stream--bug 5709
|
||||
if (impure->irsb_nav_page = bookmark->bkm_page) {
|
||||
impure->irsb_flags &= ~irsb_first;
|
||||
}
|
||||
|
||||
// store the current key value, setting up the key descriptor to point at it
|
||||
impure->irsb_nav_length = bookmark->bkm_key_desc.dsc_length;
|
||||
MOVE_FAST(bookmark->bkm_key_data, impure->irsb_nav_data,
|
||||
bookmark->bkm_key_desc.dsc_length);
|
||||
|
||||
if (impure->irsb_flags & (irsb_bof | irsb_eof | irsb_crack)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if we didn't find the record, it must have been deleted
|
||||
// from under us; the desired semantics is to be on a crack
|
||||
// at the previous position of the record
|
||||
return NAV_get_record(rsb, impure, rpb, RSE_get_current);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int compare_keys(
|
||||
const index_desc* idx,
|
||||
const UCHAR* key_string1,
|
||||
@ -1094,249 +655,6 @@ static void expand_index(WIN * window)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static bool find_dbkey(RecordSource* rsb, RecordNumber record_number)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* f i n d _ d b k e y
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Look for the record with the passed dbkey in the
|
||||
* set of records with key value equal to the current
|
||||
* record's key. This is used to find a particular
|
||||
* record within a set of equivalent keys.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
irsb_nav* impure = (IRSB_NAV) ((UCHAR *) request + rsb->rsb_impure);
|
||||
record_param* rpb = request->req_rpb + rsb->rsb_stream;
|
||||
|
||||
init_fetch(impure);
|
||||
|
||||
// if we're on a crack, this isn't going very far
|
||||
if (impure->irsb_flags & (irsb_bof | irsb_eof | irsb_crack)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// find the last fetched position from the index,
|
||||
// and get the current key value
|
||||
btree_exp* expanded_node = NULL;
|
||||
WIN window(impure->irsb_nav_page);
|
||||
btree_nod* node =
|
||||
get_position(tdbb, rsb, impure, &window, RSE_get_current,
|
||||
&expanded_node);
|
||||
temporary_key key;
|
||||
MOVE_FAST(impure->irsb_nav_data, key.key_data, impure->irsb_nav_length);
|
||||
key.key_length = impure->irsb_nav_length;
|
||||
|
||||
// In case of an error, we still need to release the window we hold
|
||||
// during the parse. See HACKs for bug 7041
|
||||
|
||||
try {
|
||||
|
||||
// loop through the equivalent values of the given key, looking for a
|
||||
// record which matches the passed dbkey
|
||||
for (;;) {
|
||||
rpb->rpb_number = get_long(node->btn_number);
|
||||
|
||||
// if we find an index entry with the proper dbkey, try to fetch the record
|
||||
if (rpb->rpb_number == record_number) {
|
||||
if (get_record(rsb, impure, rpb, &key, true)) {
|
||||
set_position(impure, rpb, &window, node, expanded_node,
|
||||
key.key_data, key.key_length);
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
return true;
|
||||
}
|
||||
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
return false;
|
||||
}
|
||||
|
||||
// go to the next node; if we find a non-equivalent node, give up
|
||||
node = BTR_next_node(node, &expanded_node);
|
||||
if (node->btn_length) {
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // try
|
||||
catch (const std::exception&) {
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static bool find_record(
|
||||
RecordSource* rsb,
|
||||
RSE_GET_MODE mode,
|
||||
temporary_key* find_key,
|
||||
USHORT find_count, USHORT search_flags)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* f i n d _ r e c o r d
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Find a record with the specified key value
|
||||
* in a stream opened on a navigational index.
|
||||
* Depending on the mode, get the first or
|
||||
* last value with the given key. This routine
|
||||
* must handle CRACK semantics.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
irsb_nav* impure = (IRSB_NAV) ((UCHAR *) request + rsb->rsb_impure);
|
||||
record_param* rpb = request->req_rpb + rsb->rsb_stream;
|
||||
WIN window(-1);
|
||||
|
||||
jrd_nod* retrieval_node = (jrd_nod*) rsb->rsb_arg[RSB_NAV_index];
|
||||
IndexRetrieval* retrieval =
|
||||
(IndexRetrieval*) retrieval_node->nod_arg[e_idx_retrieval];
|
||||
|
||||
// save the current equality retrieval key
|
||||
temporary_key* const tmp = retrieval->irb_key;
|
||||
const USHORT lower_count = retrieval->irb_lower_count;
|
||||
const USHORT upper_count = retrieval->irb_upper_count;
|
||||
|
||||
// find the page that the key value should be on
|
||||
retrieval->irb_key = find_key;
|
||||
retrieval->irb_upper_count = retrieval->irb_lower_count = find_count;
|
||||
|
||||
index_desc* idx =
|
||||
(index_desc*) ((SCHAR *) impure + (SLONG) rsb->rsb_arg[RSB_NAV_idx_offset]);
|
||||
temporary_key lower, upper;
|
||||
btree_page* page =
|
||||
BTR_find_page(tdbb, retrieval, &window, idx, &lower, &upper, false);
|
||||
|
||||
// restore the saved equality retrieval key
|
||||
retrieval->irb_key = tmp;
|
||||
retrieval->irb_lower_count = lower_count;
|
||||
retrieval->irb_upper_count = upper_count;
|
||||
|
||||
// find the appropriate leaf node
|
||||
btree_nod* node;
|
||||
while (!(node = BTR_find_leaf(page, find_key, impure->irsb_nav_data,
|
||||
0, (idx->idx_flags & idx_descending) != 0, true)))
|
||||
{
|
||||
page =
|
||||
(btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read,
|
||||
pag_index);
|
||||
}
|
||||
|
||||
btree_exp* expanded_node;
|
||||
exp_index_buf* expanded_page = window.win_expanded_buffer;
|
||||
if (expanded_page) {
|
||||
expanded_node = find_current(expanded_page, page, node);
|
||||
}
|
||||
else {
|
||||
expanded_node = NULL;
|
||||
}
|
||||
|
||||
// seed the key value with the prefix seen up to the current key
|
||||
temporary_key value;
|
||||
MOVE_FAST(impure->irsb_nav_data, value.key_data, node->btn_prefix);
|
||||
|
||||
// In case of an error, we still need to release the window we hold
|
||||
// during the parse. See HACKs for bug 7041
|
||||
|
||||
try {
|
||||
bool result = false;
|
||||
bool position_set = false;
|
||||
|
||||
// loop through the equivalent values of the given key, finding
|
||||
// a valid record if possible; for RSE_get_last, save the last
|
||||
// valid record and keep looking for more
|
||||
|
||||
// NOTE: this whole process could be made more efficient if we
|
||||
// implemented a means of finding the last index key via
|
||||
// BTR_find_page() and BTR_find_leaf(), then proceeding backwards
|
||||
// to find a valid record -deej
|
||||
|
||||
for (;;)
|
||||
{
|
||||
rpb->rpb_number = get_long(node->btn_number);
|
||||
|
||||
// if we have gone past the search key value, stop looking
|
||||
if (rpb->rpb_number == END_LEVEL) {
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_eof);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rpb->rpb_number == END_BUCKET) {
|
||||
page =
|
||||
(btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read,
|
||||
pag_index);
|
||||
node = (btree_nod*) page->btr_nodes;
|
||||
|
||||
if (expanded_page = window.win_expanded_buffer)
|
||||
expanded_node = (btree_exp*) expanded_page->exp_nodes;
|
||||
continue;
|
||||
}
|
||||
|
||||
// update the current stored key value
|
||||
value.key_length = node->btn_length + node->btn_prefix;
|
||||
UCHAR* p = value.key_data + node->btn_prefix;
|
||||
const UCHAR* q = node->btn_data;
|
||||
for (USHORT l = node->btn_length; l--;)
|
||||
*p++ = *q++;
|
||||
|
||||
// if the index key is greater than the search key, we didn't find the key
|
||||
if (compare_keys
|
||||
(idx, value.key_data, value.key_length, find_key,
|
||||
search_flags) > 0)
|
||||
{
|
||||
// if we never saw a valid record, mark as a forced crack so that
|
||||
// we will be at a position before the current record
|
||||
|
||||
if (!position_set) {
|
||||
set_position(impure, rpb, &window, node, expanded_node,
|
||||
value.key_data, value.key_length);
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack | irsb_forced_crack);
|
||||
}
|
||||
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
return result;
|
||||
}
|
||||
|
||||
// anytime we successfully retrieve a record, set position
|
||||
// to it in case we go past a viable record in looking for
|
||||
// the last record of equivalent key
|
||||
if (result = get_record(rsb, impure, rpb, &value, true)) {
|
||||
set_position(impure, rpb, &window, node, expanded_node,
|
||||
value.key_data, value.key_length);
|
||||
position_set = true;
|
||||
}
|
||||
|
||||
// if we're looking for the first record, we're done
|
||||
if (result && mode == RSE_get_first) {
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
return result;
|
||||
}
|
||||
|
||||
node = BTR_next_node(node, &expanded_node);
|
||||
}
|
||||
|
||||
} // try
|
||||
catch (const std::exception&) {
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static btree_exp* find_current(exp_index_buf* expanded_page, Ods::btree_page* page,
|
||||
const UCHAR* current_pointer)
|
||||
{
|
||||
@ -1495,17 +813,6 @@ static UCHAR* get_position(
|
||||
|
||||
exp_index_buf* expanded_page = NULL;
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
// if we are on a forced crack, don't really get the next node in
|
||||
// the forward direction, since we are really supposed to be on a
|
||||
// position before the current node
|
||||
if ((impure->irsb_flags & irsb_forced_crack)
|
||||
&& (direction == RSE_get_forward))
|
||||
{
|
||||
direction = RSE_get_current;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Re-fetch page and get incarnation counter
|
||||
Ods::btree_page* page = (Ods::btree_page*) CCH_FETCH(tdbb, window, LCK_read, pag_index);
|
||||
|
||||
|
@ -42,13 +42,5 @@ exp_index_buf* NAV_expand_index(Jrd::win*, Jrd::irsb_nav*);
|
||||
bool NAV_get_record(Jrd::thread_db* tdbb, Jrd::RecordSource*, Jrd::irsb_nav*,
|
||||
Jrd::record_param*, Jrd::rse_get_mode);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool NAV_find_record(Jrd::RecordSource*, USHORT, USHORT, Jrd::jrd_nod*);
|
||||
void NAV_get_bookmark(Jrd::RecordSource*, Jrd::irsb_nav*, Bookmark*);
|
||||
bool NAV_reset_position(Jrd::RecordSource*, Jrd::record_param*);
|
||||
bool NAV_set_bookmark(Jrd::RecordSource*, Jrd::irsb_nav*, Jrd::record_param*,
|
||||
Jrd::Bookmark*);
|
||||
#endif
|
||||
|
||||
#endif // JRD_NAV_PROTO_H
|
||||
|
||||
|
155
src/jrd/opt.cpp
155
src/jrd/opt.cpp
@ -1264,161 +1264,6 @@ int OPT_match_index(OptimizerBlk* opt, USHORT stream, index_desc* idx)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void OPT_set_index(thread_db* tdbb,
|
||||
jrd_req* request, RecordSource** rsb_ptr, jrd_rel* relation, index_desc* idx)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* O P T _ s e t _ i n d e x
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Reset the navigational order of a stream.
|
||||
* Given a sequential or navigational rsb,
|
||||
* reset the rsb to be a navigational rsb
|
||||
* on the specified index.
|
||||
*
|
||||
**************************************/
|
||||
DEV_BLKCHK(request, type_req);
|
||||
DEV_BLKCHK(*rsb_ptr, type_rsb);
|
||||
DEV_BLKCHK(relation, type_rel);
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->tdbb_database;
|
||||
|
||||
RecordSource* old_rsb = *rsb_ptr;
|
||||
|
||||
/* fix up a boolean rsb to point to the actual stream rsb */
|
||||
|
||||
if (old_rsb->rsb_type == rsb_boolean) {
|
||||
rsb_ptr = &old_rsb->rsb_next;
|
||||
old_rsb = old_rsb->rsb_next;
|
||||
}
|
||||
|
||||
/* check if there is an existing inversion for
|
||||
a boolean expression mapped to an index */
|
||||
jrd_nod* inversion = NULL;
|
||||
if (old_rsb->rsb_type == rsb_indexed) {
|
||||
inversion = (jrd_nod*) old_rsb->rsb_arg[0];
|
||||
}
|
||||
else if (old_rsb->rsb_type == rsb_navigate) {
|
||||
inversion = (jrd_nod*) old_rsb->rsb_arg[RSB_NAV_inversion];
|
||||
}
|
||||
|
||||
/* set up a dummy optimizer block just for the purposes
|
||||
of the set index, to pass information to subroutines */
|
||||
|
||||
OptimizerBlk* opt = FB_NEW(*tdbb->getDefaultPool()) OptimizerBlk(tdbb->getDefaultPool());
|
||||
opt->opt_g_flags |= opt_g_stream;
|
||||
|
||||
/* generate a new rsb for the retrieval, making sure to
|
||||
preserve the inversion generated for the last rsb; note
|
||||
that if the bitmap for the inversion has already been
|
||||
generated, it will be reused since it is already part of
|
||||
the impure area--I can't think of any reason not to reuse it--deej */
|
||||
RecordSource* new_rsb;
|
||||
if (idx) {
|
||||
new_rsb = gen_nav_rsb(tdbb, opt, old_rsb->rsb_stream, relation, 0, idx
|
||||
#ifdef SCROLLABLE_CURSORS
|
||||
, RSE_get_forward
|
||||
#endif
|
||||
);
|
||||
new_rsb->rsb_arg[RSB_NAV_inversion] = (RecordSource*) inversion;
|
||||
new_rsb->rsb_cardinality = old_rsb->rsb_cardinality;
|
||||
}
|
||||
else {
|
||||
new_rsb = gen_rsb(tdbb, opt, 0, inversion, old_rsb->rsb_stream,
|
||||
relation, 0, 0, (float) old_rsb->rsb_cardinality);
|
||||
}
|
||||
|
||||
/* point the impure area of the new rsb to the impure area of the
|
||||
old; since impure area is pre-allocated it would be difficult
|
||||
to change now, so just use the same area; NOTE: this implies
|
||||
that we must take some pains to ensure that the impure area is
|
||||
always large enough to handle a maximum-key index */
|
||||
|
||||
new_rsb->rsb_impure = old_rsb->rsb_impure;
|
||||
|
||||
/* find index node if the old rsb was navigational */
|
||||
|
||||
jrd_nod* index_node = NULL;
|
||||
if (old_rsb->rsb_type == rsb_navigate) {
|
||||
index_node = (jrd_nod*) old_rsb->rsb_arg[RSB_NAV_index];
|
||||
}
|
||||
|
||||
/* if the new rsb is navigational, set up impure space in request
|
||||
for new index node; to convert from non-navigational to navigational,
|
||||
we need to adjust the impure area upwards to make room for an impure_inversion
|
||||
structure, and vice versa to convert the other way */
|
||||
|
||||
if (idx) {
|
||||
jrd_nod* new_index_node = (jrd_nod*) new_rsb->rsb_arg[RSB_NAV_index];
|
||||
if (old_rsb->rsb_type == rsb_navigate)
|
||||
new_index_node->nod_impure = index_node->nod_impure;
|
||||
else {
|
||||
new_index_node->nod_impure = old_rsb->rsb_impure;
|
||||
new_rsb->rsb_impure += sizeof(impure_inversion);
|
||||
}
|
||||
}
|
||||
else if (old_rsb->rsb_type == rsb_navigate) {
|
||||
new_rsb->rsb_impure -= sizeof(impure_inversion);
|
||||
}
|
||||
|
||||
/* if there was a previous index, release its lock
|
||||
and remove its resource from the request */
|
||||
|
||||
if (old_rsb->rsb_type == rsb_navigate) {
|
||||
IndexRetrieval* retrieval =
|
||||
(IndexRetrieval*) index_node->nod_arg[e_idx_retrieval];
|
||||
const USHORT index_id = retrieval->irb_index;
|
||||
IndexLock* index = CMP_get_index_lock(tdbb, relation, index_id);
|
||||
if (index) {
|
||||
if (index->idl_count)
|
||||
--index->idl_count;
|
||||
if (!index->idl_count) {
|
||||
LCK_release(tdbb, index->idl_lock);
|
||||
}
|
||||
}
|
||||
CMP_release_resource(&request->req_resources, Resource::rsc_index, index_id);
|
||||
}
|
||||
|
||||
/* get lock on new index */
|
||||
|
||||
if (idx) {
|
||||
IndexLock* index = CMP_get_index_lock(tdbb, relation, idx->idx_id);
|
||||
if (index) {
|
||||
if (!index->idl_count) {
|
||||
LCK_lock_non_blocking(tdbb, index->idl_lock, LCK_SR, LCK_WAIT);
|
||||
}
|
||||
++index->idl_count;
|
||||
}
|
||||
}
|
||||
|
||||
/* go out to the vector which stores all rsbs for the
|
||||
request, and replace the old with the new */
|
||||
|
||||
for (size_t i = 0; i < request->req_fors.getCount(); i++) {
|
||||
if (request->req_fors[i] == old_rsb) {
|
||||
request->req_fors[i] = new_rsb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* release unneeded blocks */
|
||||
|
||||
delete opt;
|
||||
if (index_node) {
|
||||
delete index_node;
|
||||
}
|
||||
delete old_rsb;
|
||||
|
||||
*rsb_ptr = new_rsb;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static bool augment_stack(jrd_nod* node, NodeStack& stack)
|
||||
{
|
||||
/**************************************
|
||||
|
@ -52,10 +52,5 @@ Jrd::jrd_nod* OPT_make_index(Jrd::thread_db*, Jrd::OptimizerBlk*, Jrd::jrd_rel*,
|
||||
int OPT_match_index(Jrd::OptimizerBlk*, USHORT, Jrd::index_desc*);
|
||||
// End only exported for VMS
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void OPT_set_index(Jrd::thread_db*, Jrd::jrd_req*, Jrd::RecordSource**, Jrd::jrd_rel*,
|
||||
Jrd::index_desc*);
|
||||
#endif
|
||||
|
||||
#endif // JRD_OPT_PROTO_H
|
||||
|
||||
|
142
src/jrd/par.cpp
142
src/jrd/par.cpp
@ -2896,148 +2896,6 @@ static jrd_nod* parse(thread_db* tdbb, CompilerScratch* csb, USHORT expected,
|
||||
node = par_stream(tdbb, csb);
|
||||
break;
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
case blr_set_index:
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[e_index_stream] =
|
||||
(jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
node->nod_arg[e_index_index] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_find:
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[e_find_stream] =
|
||||
(jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
node->nod_arg[e_find_operator] = parse(tdbb, csb, VALUE);
|
||||
node->nod_arg[e_find_direction] = parse(tdbb, csb, VALUE);
|
||||
node->nod_arg[e_find_args] = par_args(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_find_dbkey:
|
||||
case blr_find_dbkey_version:
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[e_find_dbkey_stream] =
|
||||
(jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
node->nod_arg[e_find_dbkey_dbkey] = parse(tdbb, csb, VALUE);
|
||||
|
||||
if (blr_operator == blr_find_dbkey_version)
|
||||
node->nod_arg[e_find_dbkey_version] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_get_bookmark:
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[e_getmark_stream] =
|
||||
(jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
break;
|
||||
|
||||
case blr_set_bookmark:
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[e_setmark_stream] =
|
||||
(jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
node->nod_arg[e_setmark_id] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_release_bookmark:
|
||||
node->nod_arg[e_relmark_id] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_bookmark:
|
||||
node->nod_arg[e_bookmark_id] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_force_crack:
|
||||
case blr_crack:
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[0] = (jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
break;
|
||||
|
||||
case blr_reset_stream:
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[e_reset_from_stream] =
|
||||
(jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[e_reset_to_stream] =
|
||||
(jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
break;
|
||||
|
||||
case blr_release_lock:
|
||||
node->nod_arg[e_rellock_lock] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_lock_relation:
|
||||
n = BLR_BYTE;
|
||||
if (n != blr_relation && n != blr_relation2 &&
|
||||
n != blr_rid && n != blr_rid2)
|
||||
syntax_error(csb, elements[RELATION]);
|
||||
node->nod_arg[e_lockrel_relation] = par_relation(tdbb, csb, n, false);
|
||||
node->nod_arg[e_lockrel_level] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_lock_record:
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[e_lockrec_stream] =
|
||||
(jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
node->nod_arg[e_lockrec_level] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_begin_range:
|
||||
node->nod_arg[e_brange_number] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_end_range:
|
||||
node->nod_arg[e_erange_number] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_delete_range:
|
||||
node->nod_arg[e_drange_number] = parse(tdbb, csb, VALUE);
|
||||
break;
|
||||
|
||||
case blr_range_relation:
|
||||
node->nod_arg[e_range_relation_number] = parse(tdbb, csb, VALUE);
|
||||
n = BLR_BYTE;
|
||||
if (n != blr_relation && n != blr_relation2 &&
|
||||
n != blr_rid && n != blr_rid2)
|
||||
{
|
||||
syntax_error(csb, elements[RELATION]);
|
||||
}
|
||||
node->nod_arg[e_range_relation_relation] =
|
||||
par_relation(tdbb, csb, n, false);
|
||||
break;
|
||||
|
||||
case blr_release_locks:
|
||||
case blr_delete_ranges:
|
||||
node = PAR_make_node(tdbb, 0);
|
||||
node->nod_count = 0;
|
||||
break;
|
||||
|
||||
case blr_cardinality:
|
||||
n = BLR_BYTE;
|
||||
if (n >= csb->csb_rpt.getCount() || !(csb->csb_rpt[n].csb_flags & csb_used))
|
||||
error(csb, isc_ctxnotdef, 0);
|
||||
node->nod_arg[e_card_stream] =
|
||||
(jrd_nod*) (SLONG) csb->csb_rpt[n].csb_stream;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef SCROLLABLE_CURSORS
|
||||
case blr_seek:
|
||||
case blr_seek_no_warn:
|
||||
|
@ -199,10 +199,6 @@ public:
|
||||
jrd_nod* req_message; /* Current message for send/receive */
|
||||
#ifdef SCROLLABLE_CURSORS
|
||||
jrd_nod* req_async_message; /* Asynchronous message (used in scrolling) */
|
||||
#endif
|
||||
#ifdef PC_ENGINE
|
||||
vec<RefreshRange*>* req_refresh_ranges; /* Vector of refresh_ranges */
|
||||
RefreshRange* req_begin_ranges; /* Vector of refresh_ranges */
|
||||
#endif
|
||||
jrd_prc* req_procedure; /* procedure, if any */
|
||||
Firebird::MetaName req_trg_name; /* name of request (trigger), if any */
|
||||
|
835
src/jrd/rlck.cpp
835
src/jrd/rlck.cpp
@ -43,358 +43,7 @@
|
||||
|
||||
using namespace Jrd;
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static Lock* allocate_record_lock(jrd_tra*, record_param*);
|
||||
#endif
|
||||
static Lock* allocate_relation_lock(MemoryPool*, jrd_rel*);
|
||||
#ifdef PC_ENGINE
|
||||
static Lock* attachment_relation_lock(jrd_rel*);
|
||||
static void drop_record_lock(Lock*);
|
||||
static Lock* find_record_lock(record_param*);
|
||||
static bool obtain_lock(jrd_tra*, Lock*, USHORT);
|
||||
static int start_record_locking(void*);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
Lock* RLCK_lock_record(record_param* rpb,
|
||||
USHORT lock_level, lock_ast_t ast, BLK ast_arg)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ l o c k _ r e c o r d
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Lock the current record in the provided
|
||||
* record parameter block at the specified level.
|
||||
*
|
||||
**************************************/
|
||||
// SLONG process_count;
|
||||
|
||||
|
||||
/* first get a record lock on the desired record;
|
||||
if we can't get one then there is no point
|
||||
in signalling that this process needs to acquire locks */
|
||||
|
||||
Lock* lock = RLCK_lock_record_implicit(0, rpb, lock_level, ast, ast_arg);
|
||||
if (!lock)
|
||||
return NULL;
|
||||
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
|
||||
/*
|
||||
if the record is trying to be locked, check
|
||||
whether the record has already been updated on page
|
||||
by a transaction whose updates we cannot see yet--
|
||||
in which case we effectively cannot get the lock */
|
||||
|
||||
if (VIO_check_if_updated(tdbb, rpb)) {
|
||||
RLCK_unlock_record_implicit(lock, rpb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* if this process has no record locks outstanding,
|
||||
indicate through the lock manager that we are
|
||||
starting the record locking protocol */
|
||||
|
||||
jrd_rel* relation = rpb->rpb_relation;
|
||||
if (!relation->rel_explicit_locks) {
|
||||
Lock* record_locking = RLCK_record_locking(relation);
|
||||
|
||||
/* get a shared write lock to be compatible with other processes
|
||||
that are doing record locking, but incompatible with those who aren't */
|
||||
|
||||
if (record_locking->lck_logical == LCK_none)
|
||||
LCK_lock_non_blocking(tdbb, record_locking, LCK_SW, LCK_WAIT);
|
||||
else
|
||||
LCK_convert_non_blocking(tdbb, tdbb, record_locking, LCK_SW,
|
||||
LCK_WAIT);
|
||||
}
|
||||
|
||||
relation->rel_explicit_locks++;
|
||||
|
||||
return lock;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
Lock* RLCK_lock_record_implicit(jrd_tra* transaction,
|
||||
record_param* rpb,
|
||||
USHORT lock_level,
|
||||
lock_ast_t ast, BLK ast_arg)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ l o c k _ r e c o r d _ i m p l i c i t
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Lock the given record for implicit access, a subset
|
||||
* of what we need to do to lock it explicitly.
|
||||
*
|
||||
* transaction is NULL for explicit record locking.
|
||||
*
|
||||
**************************************/
|
||||
USHORT interest_lock_level = 0;
|
||||
|
||||
Lock* lock = allocate_record_lock(transaction, rpb);
|
||||
lock->lck_ast = ast;
|
||||
lock->lck_object = ast_arg;
|
||||
|
||||
/* To ensure that relation and record locks respect each other,
|
||||
utilize a multigranularity locking scheme, establishing
|
||||
an interest lock level in the parent relation according to
|
||||
the following scheme:
|
||||
read lock on record := protected read
|
||||
(implies) interest read lock on relation := shared read
|
||||
write lock on record := exclusive
|
||||
(implies) interest write lock on relation := shared write
|
||||
Then as long as PR and EX locks are used to implement read
|
||||
and write locking on relations, the relation locks will
|
||||
be respected.
|
||||
|
||||
This also guarantees that implicit record locks won't result
|
||||
in interest locks being taken out, since implicit record locks
|
||||
are SW. Relations are already implicitly reserved in
|
||||
RLCK_reserve_relation(), so there is no need for an additional
|
||||
interest lock.
|
||||
implicit read lock on record := NO LOCK
|
||||
(implies) NO interest read lock on relation
|
||||
implicit write lock on record := shared write
|
||||
(implies) interest write lock on relation := shared write
|
||||
*/
|
||||
|
||||
jrd_rel* relation = rpb->rpb_relation;
|
||||
if (lock_level == LCK_EX) {
|
||||
interest_lock_level = LCK_SW;
|
||||
relation->rel_write_locks++;
|
||||
relation->rel_lock_total++;
|
||||
}
|
||||
else if (lock_level == LCK_PR) {
|
||||
interest_lock_level = LCK_SR;
|
||||
relation->rel_read_locks++;
|
||||
relation->rel_lock_total++;
|
||||
}
|
||||
|
||||
/* first attempt to get the parent lock then get the record lock,
|
||||
using two-phase locking to help prevent deadlocks */
|
||||
|
||||
if (interest_lock_level
|
||||
&& !obtain_lock(transaction, lock->lck_parent, interest_lock_level)
|
||||
|| !obtain_lock(transaction, lock, lock_level))
|
||||
{
|
||||
RLCK_unlock_record_implicit(lock, rpb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return lock;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
Lock* RLCK_lock_relation(jrd_rel* relation,
|
||||
USHORT lock_level, lock_ast_t ast, BLK ast_arg)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ l o c k _ r e l a t i o n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Lock a relation at the specified level.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
/* allocate a relation lock hanging off the attachment
|
||||
block, then keep a count of the number of times it
|
||||
is used so that we know when to release it (bug #7478) */
|
||||
|
||||
Lock* lock = attachment_relation_lock(relation);
|
||||
lock->lck_count++;
|
||||
lock->lck_ast = ast;
|
||||
lock->lck_object = ast_arg;
|
||||
|
||||
if (!obtain_lock(0, lock, lock_level))
|
||||
{
|
||||
ERR_post(isc_relation_lock, isc_arg_string,
|
||||
relation->rel_name.c_str(), 0);
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
Lock* RLCK_range_relation(jrd_tra* transaction,
|
||||
jrd_rel* relation, lock_ast_t ast, BLK ast_arg)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ r a n g e _ r e l a t i o n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Lock a relation for a refresh range.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Attachment* attachment = tdbb->tdbb_attachment;
|
||||
|
||||
if (transaction->tra_flags & TRA_system)
|
||||
return NULL;
|
||||
|
||||
Lock* lock = allocate_relation_lock(transaction->tra_pool, relation);
|
||||
lock->lck_owner = attachment;
|
||||
lock->lck_ast = ast;
|
||||
lock->lck_object = ast_arg;
|
||||
lock->lck_type = LCK_range_relation;
|
||||
|
||||
const USHORT level = LCK_PR;
|
||||
|
||||
/* get lock */
|
||||
|
||||
const USHORT result =
|
||||
LCK_lock_non_blocking(tdbb, lock, level, transaction->getLockWait());
|
||||
|
||||
if (result)
|
||||
return lock;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
Lock* RLCK_record_locking(jrd_rel* relation)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ r e c o r d _ l o c k i n g
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Allocate a record locking lock, which determines
|
||||
* when record locking is necessary for a particular
|
||||
* relation.
|
||||
*
|
||||
**************************************/
|
||||
if (relation->rel_record_locking)
|
||||
return relation->rel_record_locking;
|
||||
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Database* dbb = GET_DBB();
|
||||
|
||||
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) Lock();
|
||||
lock->lck_parent = dbb->dbb_lock;
|
||||
lock->lck_dbb = dbb;
|
||||
lock->lck_type = LCK_record_locking;
|
||||
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
||||
|
||||
/* make the lock specific to the relation */
|
||||
|
||||
lock->lck_length = sizeof(SLONG);
|
||||
lock->lck_key.lck_long = relation->rel_id;
|
||||
relation->rel_record_locking = lock;
|
||||
|
||||
/* set up an ast to start record locking if
|
||||
someone gets an incompatible lock */
|
||||
|
||||
lock->lck_ast = start_record_locking;
|
||||
lock->lck_object = relation;
|
||||
|
||||
/* now attempt to get a PR on the lock to detect when
|
||||
anyone locks a record explicitly */
|
||||
|
||||
LCK_lock(tdbb, _non_blocking(lock, LCK_PR, LCK_NO_WAIT));
|
||||
return lock;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_release_lock(Lock* lock)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ r e l e a s e _ l o c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Release a lock of record or relation
|
||||
* type. The lock handle came from the
|
||||
* user, so validate it carefully.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
/* first do basic validation of the handle */
|
||||
|
||||
if (!lock)
|
||||
ERR_post(isc_bad_lock_handle, 0);
|
||||
if (((blk*) lock)->blk_type != (UCHAR) type_lck)
|
||||
ERR_post(isc_bad_lock_handle, 0);
|
||||
/* now use the lock type to determine the type
|
||||
of lock to release */
|
||||
if (lock->lck_type == LCK_relation)
|
||||
RLCK_unlock_relation(0, (jrd_rel*) lock->lck_object);
|
||||
else if (lock->lck_type == LCK_record)
|
||||
RLCK_unlock_record(lock, 0);
|
||||
else
|
||||
ERR_post(isc_bad_lock_handle, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_release_locks(Attachment* attachment)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ r e l e a s e _ l o c k s
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Release all relation and record locks
|
||||
* explicitly taken out during this attachment.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
// unlock all explicit relation locks
|
||||
vec<Lock*>* vector = attachment->att_relation_locks;
|
||||
if (vector) {
|
||||
vec<Lock*>::iterator lptr = vector->begin();
|
||||
for (const vec::const_iterator lend = vector->end(); lptr < lend; lptr++)
|
||||
{
|
||||
Lock* lock = *lptr;
|
||||
if (lock)
|
||||
RLCK_unlock_relation(0, (jrd_rel*) lock->lck_object);
|
||||
}
|
||||
}
|
||||
// unlock all explicit record locks
|
||||
Lock* lock;
|
||||
while (lock = attachment->att_record_locks) {
|
||||
RLCK_unlock_record(lock, 0);
|
||||
}
|
||||
// clear the vector of user locks
|
||||
if (vector = attachment->att_lck_quick_ref) {
|
||||
vec<Lock*>::iterator lptr = vector->begin();
|
||||
for (const vec<Lock*>::const_iterator lend = vector->end(); lptr < lend; lptr++)
|
||||
{
|
||||
*lptr = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Lock* RLCK_reserve_relation(thread_db* tdbb,
|
||||
@ -462,129 +111,6 @@ Lock* RLCK_reserve_relation(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_shutdown_attachment(Attachment* attachment)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ s h u t d o w n _ a t t a c h m e n t
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Shutdown the attachment's persistent record
|
||||
* and relation locks. This runs at AST level.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
/* Release child record locks before parent relation locks */
|
||||
|
||||
for (Lock* record_lock = attachment->att_record_locks;
|
||||
record_lock;
|
||||
record_lock = record_lock->lck_att_next)
|
||||
{
|
||||
LCK_release(tdbb, record_lock);
|
||||
}
|
||||
|
||||
vec<Lock*>* lock_vector = attachment->att_relation_locks;
|
||||
if (lock_vector) {
|
||||
for (vec<Lock*>::iterator lock = lock_vector->begin();
|
||||
lock != lock_vector->end(); ++lock)
|
||||
{
|
||||
if (*lock) {
|
||||
LCK_release(tdbb, *lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_shutdown_database(Database* dbb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ s h u t d o w n _ d a t a b a s e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Shutdown the database locks shared for relation
|
||||
* interest and record locking locks. This can be called
|
||||
* at AST level.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
vec<jrd_rel*>* vector = dbb->dbb_relations;
|
||||
if (!vector)
|
||||
return;
|
||||
|
||||
vec<jrd_rel*>::iterator ptr = vector->begin();
|
||||
for (const vec<jrd_rel*>::const_iterator end = vector->end(); ptr < end; ptr++)
|
||||
{
|
||||
jrd_rel* relation = *ptr;
|
||||
if (relation) {
|
||||
if (relation->rel_record_locking)
|
||||
LCK_release(tdbb, relation->rel_record_locking);
|
||||
if (relation->rel_interest_lock)
|
||||
LCK_release(tdbb, relation->rel_interest_lock);
|
||||
relation->rel_explicit_locks = 0;
|
||||
relation->rel_read_locks = 0;
|
||||
relation->rel_write_locks = 0;
|
||||
relation->rel_lock_total = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_signal_refresh(jrd_tra* transaction)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ s i g n a l _ r e f r e s h
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* For each reserved relation, get a refresh relation
|
||||
* lock to signal possible refresh range users.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Database* dbb = tdbb->tdbb_database;
|
||||
/* for each relation, take out a range relation lock and then release it */
|
||||
vec<Lock*>* vector = transaction->tra_relation_locks;
|
||||
if (vector) {
|
||||
|
||||
/* allocate a local lock */
|
||||
|
||||
Lock* local_lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) Lock();
|
||||
local_lock->lck_dbb = dbb;
|
||||
local_lock->lck_length = sizeof(SLONG);
|
||||
local_lock->lck_type = LCK_range_relation;
|
||||
local_lock->lck_owner_handle =
|
||||
LCK_get_owner_handle(tdbb, local_lock->lck_type);
|
||||
local_lock->lck_parent = dbb->dbb_lock;
|
||||
local_lock->lck_compatible = tdbb->tdbb_attachment;
|
||||
for (size_t i = 0; i < vector->count(); i++) {
|
||||
Lock* lock = (*vector)[i];
|
||||
if (lock) {
|
||||
jrd_rel* relation = (jrd_rel*) lock->lck_object;
|
||||
local_lock->lck_key.lck_long = relation->rel_id;
|
||||
local_lock->lck_object = relation;
|
||||
LCK_lock_non_blocking(tdbb, local_lock, LCK_SW, LCK_NO_WAIT);
|
||||
LCK_release(tdbb, local_lock);
|
||||
}
|
||||
}
|
||||
ALL_release(local_lock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Lock* RLCK_transaction_relation_lock(jrd_tra* transaction, jrd_rel* relation)
|
||||
{
|
||||
/**************************************
|
||||
@ -627,205 +153,6 @@ Lock* RLCK_transaction_relation_lock(jrd_tra* transaction, jrd_rel* relation)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_unlock_record(Lock* lock, record_param* rpb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ u n l o c k _ r e c o r d
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Unlock the specified record lock, or if
|
||||
* it's not available use the current record
|
||||
* in the specified record parameter block.
|
||||
*
|
||||
**************************************/
|
||||
jrd_rel* relation;
|
||||
if (rpb)
|
||||
relation = rpb->rpb_relation;
|
||||
else if (lock)
|
||||
relation = (jrd_rel*) lock->lck_parent->lck_object;
|
||||
else
|
||||
relation = NULL; /* theoretically impossible */
|
||||
|
||||
RLCK_unlock_record_implicit(lock, rpb);
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Attachment* attachment = tdbb->tdbb_attachment;
|
||||
if (attachment->att_flags & ATT_shutdown)
|
||||
return;
|
||||
/* decrement the count of explicit locks this process has taken out;
|
||||
if there are none, go back to a PR on the lock--
|
||||
if we cannot obtain this, it means someone else has explicit
|
||||
record locks taken out and we should just release the lock */
|
||||
if (relation && !--relation->rel_explicit_locks) {
|
||||
Lock* record_locking = relation->rel_record_locking;
|
||||
if (!LCK_convert_non_blocking(tdbb, record_locking, LCK_PR, LCK_NO_WAIT))
|
||||
LCK_release(tdbb, record_locking);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_unlock_record_implicit(Lock* lock, record_param* rpb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ u n l o c k _ r e c o r d _ i m p l i c i t
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Unlock a record-level lock.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
if (!lock)
|
||||
lock = find_record_lock(rpb);
|
||||
const USHORT lock_level = lock->lck_logical;
|
||||
drop_record_lock(lock);
|
||||
LCK_release(tdbb, lock);
|
||||
Attachment* attachment = tdbb->tdbb_attachment;
|
||||
if (attachment->att_flags & ATT_shutdown) {
|
||||
ALL_release(lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* handle the release half of the multigranularity locking scheme:
|
||||
if there are no more write locks, downgrade the interest
|
||||
lock on the parent relation; if there are no more read or
|
||||
write locks, release the lock entirely
|
||||
|
||||
For implicit locks, there are no relation intrest locks.
|
||||
So do nothing.
|
||||
*/
|
||||
|
||||
jrd_rel* relation = (jrd_rel*) lock->lck_parent->lck_object;
|
||||
if (lock_level == LCK_EX) {
|
||||
if (!--relation->rel_write_locks)
|
||||
if (!relation->rel_read_locks)
|
||||
LCK_release(tdbb, relation->rel_interest_lock);
|
||||
else
|
||||
LCK_convert_non_blocking(tdbb, relation->rel_interest_lock,
|
||||
LCK_SR, LCK_WAIT);
|
||||
}
|
||||
else if (lock_level == LCK_PR) {
|
||||
if (!--relation->rel_read_locks && !relation->rel_write_locks)
|
||||
LCK_release(tdbb, relation->rel_interest_lock);
|
||||
}
|
||||
|
||||
ALL_release(lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_unlock_relation(Lock* lock, jrd_rel* relation)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R L C K _ u n l o c k _ r e l a t i o n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Release the attachment's persistent lock
|
||||
* on the specified relation.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Attachment* attachment = tdbb->tdbb_attachment;
|
||||
vec<Lock*>* vector = attachment->att_relation_locks;
|
||||
if (!vector)
|
||||
return;
|
||||
|
||||
if (relation) {
|
||||
const USHORT id = relation->rel_id;
|
||||
if (id >= vector->count())
|
||||
return;
|
||||
lock = (*vector)[id];
|
||||
}
|
||||
else {
|
||||
for (int id = 0; id < vector->count(); id++)
|
||||
if (lock == (*vector)[id])
|
||||
break;
|
||||
}
|
||||
if (!lock)
|
||||
return;
|
||||
/* decrement the use count; if it goes to zero,
|
||||
there are no further locks taken out in this
|
||||
attachment so we can release the lock (bug #7478) */
|
||||
if (lock->lck_count > 1) {
|
||||
lock->lck_count--;
|
||||
return;
|
||||
}
|
||||
|
||||
LCK_release(tdbb, lock);
|
||||
ALL_release(lock);
|
||||
(*vector)[id] = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static Lock* allocate_record_lock(jrd_tra* transaction, record_param* rpb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* a l l o c a t e _ r e c o r d _ l o c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Create a record lock block for the current
|
||||
* record in the passed rpb.
|
||||
* transaction used only for implicit record locks.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Database* dbb = tdbb->tdbb_database;
|
||||
Attachment* attachment = tdbb->tdbb_attachment;
|
||||
if (!rpb->rpb_record)
|
||||
ERR_post(isc_no_cur_rec, 0);
|
||||
/* allocate a lock block for the record lock */
|
||||
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) Lock();
|
||||
lock->lck_dbb = dbb;
|
||||
lock->lck_object = reinterpret_cast<blk*>(dbb);
|
||||
lock->lck_type = LCK_record;
|
||||
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
|
||||
/* use the relation lock as the lock parent */
|
||||
jrd_rel* relation = rpb->rpb_relation;
|
||||
if (transaction)
|
||||
lock->lck_parent =
|
||||
RLCK_transaction_relation_lock(transaction, relation);
|
||||
else {
|
||||
if (!relation->rel_interest_lock)
|
||||
relation->rel_interest_lock =
|
||||
allocate_relation_lock(dbb->dbb_permanent, relation);
|
||||
lock->lck_parent = relation->rel_interest_lock;
|
||||
}
|
||||
|
||||
/* indicate that this lock should be compatible at the attachment
|
||||
level--meaning that two record locks taken out within the same
|
||||
attachment should always be compatible; ditto for the interest lock */
|
||||
|
||||
lock->lck_compatible = attachment;
|
||||
lock->lck_parent->lck_compatible = attachment;
|
||||
/* link in the record lock with the other record locks
|
||||
taken out by this attachment */
|
||||
lock->lck_att_next = attachment->att_record_locks;
|
||||
attachment->att_record_locks = lock;
|
||||
/* fill in the lock value using the record number */
|
||||
lock->lck_length = sizeof(SLONG);
|
||||
lock->lck_key.lck_long = rpb->rpb_number;
|
||||
return lock;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static Lock* allocate_relation_lock(MemoryPool* pool, jrd_rel* relation)
|
||||
{
|
||||
/**************************************
|
||||
@ -856,165 +183,3 @@ static Lock* allocate_relation_lock(MemoryPool* pool, jrd_rel* relation)
|
||||
return lock;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static Lock* attachment_relation_lock(jrd_rel* relation)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* a t t a c h m e n t _ r e l a t i o n _ l o c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Take out a persistent relation lock at the
|
||||
* attachment level.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Database* dbb = tdbb->tdbb_database;
|
||||
Attachment* attachment = tdbb->tdbb_attachment;
|
||||
|
||||
Lock* lock;
|
||||
vec<Lock*>* vector = attachment->att_relation_locks;
|
||||
if (vector &&
|
||||
(relation->rel_id < vector->count()) &&
|
||||
(lock = (*vector)[relation->rel_id]))
|
||||
{
|
||||
return lock;
|
||||
}
|
||||
|
||||
vector = attachment->att_relation_locks =
|
||||
vec<Lock*>::newVector(*dbb->dbb_permanent, attachment->att_relation_locks,
|
||||
relation->rel_id + 1);
|
||||
|
||||
if ( (lock = (*vector)[relation->rel_id]) )
|
||||
return lock;
|
||||
|
||||
lock = allocate_relation_lock(dbb->dbb_permanent, relation);
|
||||
lock->lck_owner = attachment;
|
||||
(*vector)[relation->rel_id] = lock;
|
||||
|
||||
return lock;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static void drop_record_lock(Lock* record_lock)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* d r o p _ r e c o r d _ l o c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Find the record lock in the linked list off
|
||||
* the attachment block, and drop it from the list.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
/* look through all the record locks taken out by this attachment
|
||||
looking for one with the same record number and relation id */
|
||||
Attachment* attachment = tdbb->tdbb_attachment;
|
||||
for (Lock** lock = &attachment->att_record_locks; *lock;
|
||||
lock = &(*lock)->lck_att_next)
|
||||
{
|
||||
if (*lock == record_lock) {
|
||||
*lock = (*lock)->lck_att_next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static Lock* find_record_lock(record_param* rpb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* f i n d _ r e c o r d _ l o c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Find the record lock previously
|
||||
* defined for a record.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
/* look through all the record locks taken out by this attachment
|
||||
looking for one with the same record number and relation */
|
||||
Attachment* attachment = tdbb->tdbb_attachment;
|
||||
Lock* lock;
|
||||
for (lock = attachment->att_record_locks; lock; lock = lock->lck_att_next)
|
||||
{
|
||||
if ((rpb->rpb_number == lock->lck_key.lck_long)
|
||||
&& (rpb->rpb_relation == (jrd_rel*) lock->lck_parent->lck_object))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static bool obtain_lock(jrd_tra* transaction, Lock* lock, USHORT lock_level)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* o b t a i n _ l o c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Obtain the specified lock at the
|
||||
* necessary level.
|
||||
*
|
||||
**************************************/
|
||||
const SSHORT wait_flag =
|
||||
transaction ? transaction->getLockWait() : 0;
|
||||
/* return if lock level OK and if the lock has not been released
|
||||
(like as part of a refresh range) */
|
||||
if ((lock_level <= lock->lck_logical) && (lock->lck_id != -1))
|
||||
return true;
|
||||
if ((lock->lck_logical) && (lock->lck_id != -1)) {
|
||||
if (LCK_convert_non_blocking(NULL, lock, lock_level, wait_flag))
|
||||
return true;
|
||||
}
|
||||
else if (LCK_lock_non_blocking(NULL, lock, lock_level, wait_flag))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static int start_record_locking(void* relation_void)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* s t a r t _ r e c o r d _ l o c k i n g
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* A blocking AST has been issued to give up
|
||||
* the lock on the record locking semaphore.
|
||||
* Flag the fact that record locking is now
|
||||
* necessary for reading and writing records.
|
||||
*
|
||||
**************************************/
|
||||
jrd_rel* relation = static_cast<jrd_rel*>(relation_void);
|
||||
Lock* record_locking = relation->rel_record_locking;
|
||||
/* if we have shared write, it means we have records
|
||||
locked; we won't give up this lock for anyone! */
|
||||
if (record_locking->lck_physical == LCK_SW)
|
||||
return 0;
|
||||
ISC_ast_enter();
|
||||
LCK_release(NULL, record_locking);
|
||||
ISC_ast_exit();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -32,36 +32,10 @@ namespace Jrd {
|
||||
class Attachment;
|
||||
class thread_db;
|
||||
}
|
||||
struct blk;
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
Jrd::Lock* RLCK_lock_record(Jrd::record_param*, USHORT, lock_ast_t, blk*);
|
||||
|
||||
Jrd::Lock* RLCK_lock_record_implicit(Jrd::jrd_tra*, Jrd::record_param*,
|
||||
USHORT, lock_ast_t, blk*);
|
||||
Jrd::Lock* RLCK_lock_relation(Jrd::jrd_rel*, USHORT, lock_ast_t, blk*);
|
||||
Jrd::Lock* RLCK_range_relation(Jrd::jrd_tra*, Jrd::jrd_rel*, lock_ast_t, blk*);
|
||||
Jrd::Lock* RLCK_record_locking(Jrd::jrd_rel*);
|
||||
void RLCK_release_lock(Jrd::Lock*);
|
||||
void RLCK_release_locks(Jrd::Attachment*);
|
||||
#endif
|
||||
|
||||
Jrd::Lock* RLCK_reserve_relation(Jrd::thread_db*, Jrd::jrd_tra*,
|
||||
Jrd::jrd_rel*, bool, bool);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_shutdown_attachment(Jrd::Attachment*);
|
||||
void RLCK_shutdown_database(Jrd::Database*);
|
||||
void RLCK_signal_refresh(Jrd::jrd_tra*);
|
||||
#endif
|
||||
|
||||
Jrd::Lock* RLCK_transaction_relation_lock(Jrd::jrd_tra*, Jrd::jrd_rel*);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RLCK_unlock_record(Lock*, Jrd::record_param*);
|
||||
void RLCK_unlock_record_implicit(Lock*, Jrd::record_param*);
|
||||
void RLCK_unlock_relation(Lock*, Jrd::jrd_rel*);
|
||||
#endif
|
||||
|
||||
#endif // JRD_RLCK_PROTO_H
|
||||
|
||||
|
469
src/jrd/rse.cpp
469
src/jrd/rse.cpp
@ -225,186 +225,6 @@ void RSE_close(thread_db* tdbb, RecordSource* rsb)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool RSE_find_dbkey(thread_db* tdbb, RecordSource* rsb, jrd_nod* find_key, jrd_nod* record_version)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R S E _ f i n d _ d b k e y
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Find the passed dbkey in the stream
|
||||
* with equivalent key values. Optionally,
|
||||
* check for a record version also.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
|
||||
/* get the record number from the passed dbkey */
|
||||
|
||||
const dsc* desc = EVL_expr(tdbb, find_key);
|
||||
|
||||
ULONG dbkey[2];
|
||||
dsc desc2;
|
||||
desc2.dsc_address = (UCHAR *) dbkey;
|
||||
desc2.dsc_length = sizeof(dbkey);
|
||||
desc2.dsc_dtype = dtype_text;
|
||||
desc2.dsc_scale = 0;
|
||||
desc2.dsc_sub_type = ttype_binary;
|
||||
desc2.dsc_flags = 0;
|
||||
|
||||
MOV_move(desc, &desc2);
|
||||
|
||||
/* now get the record version to use in comparing
|
||||
against the tid of the record */
|
||||
|
||||
ULONG version_number;
|
||||
if (record_version) {
|
||||
desc = EVL_expr(tdbb, record_version);
|
||||
|
||||
desc2.dsc_address = (UCHAR *) & version_number;
|
||||
desc2.dsc_length = sizeof(version_number);
|
||||
desc2.dsc_dtype = dtype_text;
|
||||
desc2.dsc_scale = 0;
|
||||
desc2.dsc_sub_type = ttype_binary;
|
||||
desc2.dsc_flags = 0;
|
||||
|
||||
MOV_move(desc, &desc2);
|
||||
}
|
||||
|
||||
record_param* rpb;
|
||||
irsb_index* impure;
|
||||
RecordBitmap* bitmap;
|
||||
|
||||
switch (rsb->rsb_type) {
|
||||
case rsb_boolean:
|
||||
if (!RSE_find_dbkey(tdbb, rsb->rsb_next, find_key, record_version))
|
||||
return false;
|
||||
|
||||
if ((rsb->rsb_arg[0]) && (!EVL_boolean(tdbb, rsb->rsb_arg[0]))) {
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case rsb_navigate:
|
||||
rpb = request->req_rpb + rsb->rsb_stream;
|
||||
rpb->rpb_number = dbkey[1] - 1;
|
||||
|
||||
/* first, fetch the indicated record */
|
||||
|
||||
if (!VIO_get
|
||||
(tdbb, rpb, rsb, request->req_transaction,
|
||||
request->req_pool))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (record_version && version_number != rpb->rpb_transaction_nr)
|
||||
return false;
|
||||
|
||||
/* next, set the stream position to that of the fetched record */
|
||||
|
||||
RSE_MARK_CRACK(tdbb, rsb, 0);
|
||||
if (NAV_reset_position(rsb, rpb))
|
||||
return true;
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
|
||||
case rsb_sequential:
|
||||
rpb = request->req_rpb + rsb->rsb_stream;
|
||||
rpb->rpb_number = dbkey[1] - 1;
|
||||
|
||||
RSE_MARK_CRACK(tdbb, rsb, 0);
|
||||
if (VIO_get
|
||||
(tdbb, rpb, rsb, request->req_transaction, request->req_pool)
|
||||
&& (!record_version || version_number == rpb->rpb_transaction_nr))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
|
||||
case rsb_indexed:
|
||||
rpb = request->req_rpb + rsb->rsb_stream;
|
||||
rpb->rpb_number = dbkey[1] - 1;
|
||||
impure = (irsb_index*) ((UCHAR *) request + rsb->rsb_impure);
|
||||
|
||||
RSE_MARK_CRACK(tdbb, rsb, 0);
|
||||
if ((bitmap = impure->irsb_bitmap) &&
|
||||
SBM_next(*bitmap, &rpb->rpb_number, RSE_get_current) &&
|
||||
VIO_get(tdbb, rpb, rsb, request->req_transaction,
|
||||
request->req_pool) &&
|
||||
(!record_version || version_number == rpb->rpb_transaction_nr))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
|
||||
default:
|
||||
BUGCHECK(166); /* msg 166 invalid rsb type */
|
||||
return false; /* Added to remove compiler warnings */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool RSE_find_record(thread_db* tdbb,
|
||||
RecordSource* rsb,
|
||||
USHORT blr_operator, USHORT direction, jrd_nod* find_key)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R S E _ f i n d _ r e c o r d
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Find the record with the passed key
|
||||
* value, using the passed operator to
|
||||
* compare records with the key value.
|
||||
* Search forwards or backwards.
|
||||
*
|
||||
**************************************/
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
switch (rsb->rsb_type) {
|
||||
case rsb_indexed:
|
||||
return RSE_find_record(tdbb, rsb->rsb_next, blr_operator, direction,
|
||||
find_key);
|
||||
|
||||
case rsb_boolean:
|
||||
if (!RSE_find_record
|
||||
(tdbb, rsb->rsb_next, blr_operator, direction, find_key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((rsb->rsb_arg[0]) && (!EVL_boolean(tdbb, rsb->rsb_arg[0]))) {
|
||||
RSE_MARK_CRACK(tdbb, rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case rsb_navigate:
|
||||
return NAV_find_record(rsb, blr_operator, direction, find_key);
|
||||
|
||||
default:
|
||||
BUGCHECK(166); /* msg 166 invalid rsb type */
|
||||
return false; /* Added to remove compiler warnings */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool RSE_get_record(thread_db* tdbb, RecordSource* rsb, RSE_GET_MODE mode)
|
||||
{
|
||||
/**************************************
|
||||
@ -503,106 +323,6 @@ bool RSE_get_record(thread_db* tdbb, RecordSource* rsb, RSE_GET_MODE mode)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
Bookmark* RSE_get_bookmark(thread_db* tdbb, RecordSource* rsb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R S E _ g e t _ b o o k m a r k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Return a descriptor whose value is a pointer
|
||||
* to a bookmark describing the location of
|
||||
* the current record in a navigational stream.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
if (request->req_flags & req_abort)
|
||||
return FALSE;
|
||||
|
||||
switch (rsb->rsb_type) {
|
||||
case rsb_boolean:
|
||||
return RSE_get_bookmark(rsb->rsb_next);
|
||||
|
||||
case rsb_navigate:
|
||||
{
|
||||
IRSB_NAV impure = (IRSB_NAV) ((UCHAR *) request + rsb->rsb_impure);
|
||||
Bookmark* bookmark = BKM_allocate(rsb, impure->irsb_nav_length);
|
||||
NAV_get_bookmark(rsb, impure, bookmark);
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
case rsb_indexed:
|
||||
case rsb_sequential:
|
||||
{
|
||||
record_param* rpb = request->req_rpb + rsb->rsb_stream;
|
||||
Bookmark* bookmark = BKM_allocate(rsb, (USHORT) 0);
|
||||
bookmark->bkm_number = rpb->rpb_number;
|
||||
bookmark->bkm_key_desc.dsc_dtype = dtype_long;
|
||||
bookmark->bkm_key_desc.dsc_length = sizeof(bookmark->bkm_number);
|
||||
bookmark->bkm_key_desc.dsc_address = (UCHAR *) & bookmark->bkm_number;
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
default:
|
||||
BUGCHECK(166); /* msg 166 invalid rsb type */
|
||||
return FALSE; /* Added to remove compiler warnings */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
void RSE_mark_crack(thread_db* tdbb, RecordSource* rsb, USHORT flags)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R S E _ m a r k _ c r a c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Position stream on a crack.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
|
||||
/* correct boolean rsbs to point to the "real" rsb */
|
||||
|
||||
if (rsb->rsb_type == rsb_boolean)
|
||||
rsb = rsb->rsb_next;
|
||||
|
||||
/* clear all the flag bits first to make sure
|
||||
no conflicting bits are set */
|
||||
|
||||
irsb* impure = (IRSB) ((UCHAR *) request + rsb->rsb_impure);
|
||||
impure->irsb_flags &=
|
||||
~(irsb_bof | irsb_eof | irsb_crack | irsb_forced_crack);
|
||||
|
||||
impure->irsb_flags |= flags;
|
||||
|
||||
/* release the current record to make sure
|
||||
that no one erroneously tries to retrieve it */
|
||||
|
||||
if (flags) {
|
||||
record_param* rpb = &request->req_rpb[rsb->rsb_stream];
|
||||
if (rpb->rpb_record) {
|
||||
delete rpb->rpb_record;
|
||||
rpb->rpb_record = NULL;
|
||||
}
|
||||
if (rpb->rpb_copy) {
|
||||
delete rpb->rpb_copy;
|
||||
rpb->rpb_copy = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void RSE_open(thread_db* tdbb, RecordSource* rsb)
|
||||
{
|
||||
/**************************************
|
||||
@ -808,129 +528,6 @@ void RSE_open(thread_db* tdbb, RecordSource* rsb)
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool RSE_reset_position(thread_db* tdbb, RecordSource* rsb, record_param* new_rpb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R S E _ r e s e t _ p o s i t i o n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Reset the position of a navigational stream to
|
||||
* the position indicated by the passed record.
|
||||
*
|
||||
**************************************/
|
||||
record_param* rpb;
|
||||
irsb_index* impure;
|
||||
RecordBitmap* bitmap;
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
if (request->req_flags & req_abort)
|
||||
return false;
|
||||
|
||||
switch (rsb->rsb_type) {
|
||||
case rsb_boolean:
|
||||
return RSE_reset_position(rsb->rsb_next, new_rpb);
|
||||
|
||||
case rsb_navigate:
|
||||
RSE_MARK_CRACK(rsb, 0);
|
||||
if (!(NAV_reset_position(rsb, new_rpb))) {
|
||||
RSE_MARK_CRACK(rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case rsb_sequential:
|
||||
RSE_MARK_CRACK(rsb, 0);
|
||||
rpb = request->req_rpb + rsb->rsb_stream;
|
||||
rpb->rpb_number = new_rpb->rpb_number;
|
||||
|
||||
if (!
|
||||
(VIO_get
|
||||
(tdbb, rpb, rsb, request->req_transaction, request->req_pool)))
|
||||
{
|
||||
RSE_MARK_CRACK(rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case rsb_indexed:
|
||||
RSE_MARK_CRACK(rsb, 0);
|
||||
rpb = request->req_rpb + rsb->rsb_stream;
|
||||
rpb->rpb_number = new_rpb->rpb_number;
|
||||
|
||||
impure = (irsb_index*) ((UCHAR *) request + rsb->rsb_impure);
|
||||
if ((bitmap = impure->irsb_bitmap) &&
|
||||
SBM_next(*bitmap, &rpb->rpb_number, RSE_get_current) &&
|
||||
VIO_get(tdbb, rpb, rsb, request->req_transaction,
|
||||
request->req_pool))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
RSE_MARK_CRACK(rsb, irsb_crack);
|
||||
return false;
|
||||
|
||||
default:
|
||||
BUGCHECK(166); /* msg 166 invalid rsb type */
|
||||
return false; /* Added to remove compiler warnings */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool RSE_set_bookmark(thread_db* tdbb, RecordSource* rsb, record_param* rpb, Bookmark* bookmark)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* R S E _ s e t _ b o o k m a r k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Set the location of a stream to the location
|
||||
* specified by the given bookmark.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
jrd_req* request = tdbb->tdbb_request;
|
||||
if (request->req_flags & req_abort)
|
||||
return false;
|
||||
|
||||
IRSB impure = (IRSB) ((UCHAR *) request + rsb->rsb_impure);
|
||||
|
||||
switch (rsb->rsb_type) {
|
||||
case rsb_boolean:
|
||||
return RSE_set_bookmark(rsb->rsb_next, rpb, bookmark);
|
||||
|
||||
case rsb_navigate:
|
||||
return NAV_set_bookmark(rsb, impure, rpb, bookmark);
|
||||
|
||||
case rsb_sequential:
|
||||
case rsb_indexed:
|
||||
rpb->rpb_number = bookmark->bkm_number;
|
||||
|
||||
if (impure->irsb_flags & (irsb_bof | irsb_eof | irsb_crack))
|
||||
return false;
|
||||
|
||||
if (!(get_record(tdbb, rsb, NULL, RSE_get_current))) {
|
||||
RSE_MARK_CRACK(rsb, irsb_crack);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
BUGCHECK(166); /* msg 166 invalid rsb type */
|
||||
return false; /* Added to remove compiler warnings */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void close_merge(thread_db* tdbb, RecordSource* rsb, irsb_mrg* impure)
|
||||
{
|
||||
/**************************************
|
||||
@ -2232,12 +1829,8 @@ static bool get_record(thread_db* tdbb,
|
||||
{
|
||||
if (((mode == RSE_get_forward) && (impure->irsb_flags & irsb_eof)) ||
|
||||
((mode == RSE_get_backward) && (impure->irsb_flags & irsb_bof)))
|
||||
#ifdef PC_ENGINE
|
||||
||((mode == RSE_get_current)
|
||||
&& (impure->irsb_flags & (irsb_bof | irsb_eof)))
|
||||
#endif
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -2252,34 +1845,20 @@ static bool get_record(thread_db* tdbb,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
if (mode == RSE_get_current)
|
||||
{
|
||||
if (!VIO_get(tdbb,
|
||||
rpb,
|
||||
rsb,
|
||||
request->req_transaction,
|
||||
request->req_pool))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!VIO_next_record(tdbb,
|
||||
rpb,
|
||||
rsb,
|
||||
request->req_transaction,
|
||||
request->req_pool,
|
||||
if (!VIO_next_record(tdbb,
|
||||
rpb,
|
||||
rsb,
|
||||
request->req_transaction,
|
||||
request->req_pool,
|
||||
#ifdef SCROLLABLE_CURSORS
|
||||
(mode == RSE_get_backward),
|
||||
(mode == RSE_get_backward),
|
||||
#else
|
||||
false,
|
||||
false,
|
||||
#endif
|
||||
false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case rsb_indexed:
|
||||
@ -2398,10 +1977,6 @@ static bool get_record(thread_db* tdbb,
|
||||
any_true = true;
|
||||
break;
|
||||
}
|
||||
#ifdef PC_ENGINE
|
||||
else if (mode == RSE_get_current)
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* check for select stream and nulls */
|
||||
|
||||
@ -2458,10 +2033,6 @@ static bool get_record(thread_db* tdbb,
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
#ifdef PC_ENGINE
|
||||
else if (mode == RSE_get_current)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
request->req_flags &= ~req_null;
|
||||
if (result)
|
||||
@ -2510,10 +2081,6 @@ static bool get_record(thread_db* tdbb,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef PC_ENGINE
|
||||
else if (mode == RSE_get_current)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
request->req_flags &= ~req_null;
|
||||
if (any_false)
|
||||
@ -2557,10 +2124,6 @@ static bool get_record(thread_db* tdbb,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef PC_ENGINE
|
||||
else if (mode == RSE_get_current)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
request->req_flags &= ~req_null;
|
||||
if (any_false)
|
||||
@ -2580,14 +2143,6 @@ static bool get_record(thread_db* tdbb,
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
#ifdef PC_ENGINE
|
||||
/* If we are trying to "RSE_get_current" and there is a
|
||||
* "where" clause which is not true, someone must have
|
||||
* modified it after we positioned on the record
|
||||
*/
|
||||
else if (mode == RSE_get_current)
|
||||
break;
|
||||
#endif
|
||||
|
||||
if (request->req_flags & req_null)
|
||||
flag = true;
|
||||
|
@ -34,26 +34,9 @@ namespace Jrd {
|
||||
}
|
||||
|
||||
void RSE_close(Jrd::thread_db*, Jrd::RecordSource*);
|
||||
#ifdef PC_ENGINE
|
||||
bool RSE_find_dbkey(Jrd::thread_db*, Jrd::RecordSource*, Jrd::jrd_nod*, Jrd::jrd_nod*);
|
||||
bool RSE_find_record(Jrd::thread_db*, Jrd::RecordSource*, USHORT, USHORT, Jrd::jrd_nod*);
|
||||
#endif
|
||||
bool RSE_get_record(Jrd::thread_db*, Jrd::RecordSource*, Jrd::rse_get_mode);
|
||||
#ifdef PC_ENGINE
|
||||
Bookmark* RSE_get_bookmark(Jrd::thread_db*, Jrd::RecordSource*);
|
||||
void RSE_mark_crack(Jrd::thread_db*, Jrd::RecordSource*, USHORT);
|
||||
#endif
|
||||
void RSE_open(Jrd::thread_db*, Jrd::RecordSource*);
|
||||
#ifdef PC_ENGINE
|
||||
bool RSE_reset_position(Jrd::thread_db*, Jrd::RecordSource*, Jrd::record_param*);
|
||||
bool RSE_set_bookmark(Jrd::thread_db*, Jrd::RecordSource*, Jrd::record_param*, Jrd::Bookmark*);
|
||||
#endif
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
#define RSE_MARK_CRACK(t, var1, var2) RSE_mark_crack (t, var1, var2)
|
||||
#else
|
||||
#define RSE_MARK_CRACK(t, var1, var2)
|
||||
#endif
|
||||
|
||||
#endif // JRD_RSE_PROTO_H
|
||||
|
||||
|
@ -523,10 +523,6 @@ static bool shutdown_locks(Database* dbb, SSHORT flag)
|
||||
if (attachment->att_id_lock)
|
||||
LCK_release(tdbb, attachment->att_id_lock);
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
RNG_shutdown_attachment(attachment);
|
||||
RLCK_shutdown_attachment(attachment);
|
||||
#endif
|
||||
TRA_shutdown_attachment(tdbb, attachment);
|
||||
}
|
||||
|
||||
@ -535,9 +531,6 @@ static bool shutdown_locks(Database* dbb, SSHORT flag)
|
||||
as, relation interest and record locking locks for PC semantic
|
||||
record locking. */
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
RLCK_shutdown_database(dbb);
|
||||
#endif
|
||||
CMP_shutdown_database(tdbb);
|
||||
|
||||
/* If shutdown manager is here, leave enough database lock context
|
||||
|
@ -19,7 +19,7 @@
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
* $Id: sort.cpp,v 1.75 2005-05-27 22:44:05 asfernandes Exp $
|
||||
* $Id: sort.cpp,v 1.76 2006-02-02 07:32:07 robocop Exp $
|
||||
*
|
||||
* 2001-09-24 SJL - Temporary fix for large sort file bug
|
||||
*
|
||||
@ -624,17 +624,6 @@ void SORT_get(ISC_STATUS * status_vector,
|
||||
scb->scb_next_pointer++;
|
||||
break;
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
case RSE_get_current:
|
||||
if (scb->scb_next_pointer <= scb->scb_first_pointer ||
|
||||
scb->scb_next_pointer > scb->scb_last_pointer)
|
||||
{
|
||||
record = NULL;
|
||||
}
|
||||
record = *scb->scb_next_pointer;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
fb_assert(FALSE);
|
||||
break;
|
||||
|
@ -109,9 +109,6 @@ static void retain_context(thread_db*, jrd_tra*, bool, SSHORT);
|
||||
#ifdef VMS
|
||||
static void compute_oldest_retaining(thread_db*, jrd_tra*, bool);
|
||||
#endif
|
||||
#ifdef PC_ENGINE
|
||||
static int downgrade_lock(void*);
|
||||
#endif
|
||||
static void expand_view_lock(jrd_tra*, jrd_rel*, SCHAR);
|
||||
static tx_inv_page* fetch_inventory_page(thread_db*, WIN *, SLONG, USHORT);
|
||||
static SLONG inventory_page(thread_db*, SLONG);
|
||||
@ -461,12 +458,6 @@ void TRA_commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_flag
|
||||
}
|
||||
#endif
|
||||
|
||||
/* signal refresh range relations for ExpressLink */
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
RLCK_signal_refresh(transaction);
|
||||
#endif
|
||||
|
||||
if (retaining_flag) {
|
||||
retain_context(tdbb, transaction, true, tra_committed);
|
||||
return;
|
||||
@ -1285,9 +1276,7 @@ void TRA_rollback(thread_db* tdbb, jrd_tra* transaction, const bool retaining_fl
|
||||
state = tra_committed;
|
||||
}
|
||||
|
||||
/* if this is a rollback retain (used only by ExpressLink), abort
|
||||
* this transaction and start a new one.
|
||||
*/
|
||||
// If this is a rollback retain abort this transaction and start a new one.
|
||||
|
||||
if (retaining_flag) {
|
||||
retain_context(tdbb, transaction, false, state);
|
||||
@ -1585,12 +1574,6 @@ jrd_tra* TRA_start(thread_db* tdbb, int tpb_length, const SCHAR* tpb)
|
||||
trans->tra_lock = lock;
|
||||
lock->lck_key.lck_long = number;
|
||||
|
||||
/* Support refresh range notification in ExpressLink */
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
lock->lck_ast = downgrade_lock;
|
||||
#endif
|
||||
|
||||
/* Put the TID of the oldest active transaction (from the header page)
|
||||
in the new transaction's lock. */
|
||||
|
||||
@ -2330,60 +2313,6 @@ static void compute_oldest_retaining(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
static int downgrade_lock(void* transaction_void)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* d o w n g r a d e _ l o c k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Someone is trying to establish an interest
|
||||
* lock in this transaction. Downgrade to a
|
||||
* shared write, to allow transactions to wait
|
||||
* on this transaction or, alternatively, be
|
||||
* notified if and when the transaction commits.
|
||||
*
|
||||
**************************************/
|
||||
ISC_ast_enter();
|
||||
jrd_tra* transaction = static_cast<jrd_tra*>(transaction_void);
|
||||
|
||||
/* Since this routine will be called asynchronously, we must establish
|
||||
a thread context. */
|
||||
|
||||
thread_db thd_context, *tdbb;
|
||||
JRD_set_thread_data(tdbb, thd_context);
|
||||
|
||||
/* Ignore the request if the transaction or lock block does not appear
|
||||
to be valid or if the lock is not a write lock. */
|
||||
|
||||
if (transaction->tra_use_count);
|
||||
else {
|
||||
tdbb->tdbb_database = transaction->tra_attachment->att_database;
|
||||
tdbb->tdbb_attachment = transaction->tra_attachment;
|
||||
tdbb->tdbb_quantum = QUANTUM;
|
||||
tdbb->tdbb_request = NULL;
|
||||
tdbb->tdbb_transaction = transaction;
|
||||
|
||||
++transaction->tra_use_count;
|
||||
Lock* lock = transaction->tra_lock;
|
||||
if (lock && lock->lck_logical == LCK_write) {
|
||||
lock->lck_ast = NULL;
|
||||
LCK_convert(tdbb, lock, LCK_SW, TRUE);
|
||||
}
|
||||
--transaction->tra_use_count;
|
||||
}
|
||||
|
||||
/* Restore the prior thread context */
|
||||
|
||||
JRD_restore_thread_data();
|
||||
|
||||
ISC_ast_exit();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void expand_view_lock(jrd_tra* transaction, jrd_rel* relation, SCHAR lock_type)
|
||||
{
|
||||
@ -2638,12 +2567,6 @@ static void retain_context(thread_db* tdbb, jrd_tra* transaction,
|
||||
new_lock->lck_key.lck_long = new_number;
|
||||
new_lock->lck_data = transaction->tra_lock->lck_data;
|
||||
|
||||
/* Support refresh range notification in ExpressLink */
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
new_lock->lck_ast = downgrade_lock;
|
||||
#endif
|
||||
|
||||
if (!LCK_lock_non_blocking(tdbb, new_lock, LCK_write, LCK_WAIT)) {
|
||||
#ifndef SUPERSERVER_V2
|
||||
if (!(dbb->dbb_flags & DBB_read_only))
|
||||
|
@ -105,9 +105,6 @@ class jrd_tra : public pool_alloc_rpt<SCHAR, type_tra>
|
||||
Savepoint* tra_save_point; /* list of savepoints */
|
||||
SLONG tra_save_point_number; /* next save point number to use */
|
||||
ULONG tra_flags;
|
||||
#ifdef PC_ENGINE
|
||||
SLONG tra_range_id; /* unique id of cache range within transaction */
|
||||
#endif
|
||||
class DeferredWork* tra_deferred_work; /* work deferred to commit time */
|
||||
ResourceList tra_resources; /* resource existence list */
|
||||
Firebird::StringMap tra_context_vars; // Context variables for the transaction
|
||||
|
120
src/jrd/vio.cpp
120
src/jrd/vio.cpp
@ -761,18 +761,6 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, RecordSource*
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
/* for refresh ranges, we want to know about uncommitted record versions */
|
||||
|
||||
if (rsb) {
|
||||
const jrd_req* request = tdbb->tdbb_request;
|
||||
const irsb_nav* impure = (IRSB_NAV) ((UCHAR *) request + rsb->rsb_impure);
|
||||
if (impure->irsb_flags & irsb_refresh) {
|
||||
RNG_add_uncommitted_record(rpb);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* we can't use this one so if there aren't any more just stop now. */
|
||||
|
||||
if (rpb->rpb_b_page == 0) {
|
||||
@ -962,103 +950,6 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, RecordSource*
|
||||
}
|
||||
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
bool VIO_check_if_updated(thread_db* tdbb, record_param* rpb)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* V I O _ c h e c k _ i f _ u p d a t e d
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Check to see if the record specified in the passed
|
||||
* rpb has been updated by an uncommitted transaction.
|
||||
* This involves looking at the latest and greatest
|
||||
* version of the record, checking its transaction id,
|
||||
* then checking the TIP page to see if that transaction
|
||||
* has been committed.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
/* loop through till we find a real version of the record;
|
||||
one that isn't going to be garbage collected */
|
||||
|
||||
jrd_tra* transaction = tdbb->tdbb_request->req_transaction;
|
||||
|
||||
while (true) {
|
||||
if (!DPM_get(tdbb, rpb, LCK_read)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
CCH_RELEASE(tdbb, &rpb->rpb_window);
|
||||
}
|
||||
|
||||
/* if the system transaction updated this record,
|
||||
it automatically is considered committed */
|
||||
|
||||
if (!rpb->rpb_transaction_nr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rpb->rpb_transaction_nr == transaction->tra_number) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* get the state of the given transaction */
|
||||
|
||||
USHORT state = TRA_get_state(tdbb, rpb->rpb_transaction_nr);
|
||||
|
||||
/* Reset the garbage collect active flag if the transaction state is
|
||||
in a terminal state. If committed it must have been a precommitted
|
||||
transaction that was backing out a dead record version and the
|
||||
system crashed. Clear the flag and set the state to tra_dead to
|
||||
reattempt the backout. */
|
||||
|
||||
if (rpb->rpb_flags & rpb_gc_active) {
|
||||
switch (state) {
|
||||
case tra_committed:
|
||||
state = tra_dead;
|
||||
rpb->rpb_flags &= ~rpb_gc_active;
|
||||
break;
|
||||
|
||||
case tra_dead:
|
||||
rpb->rpb_flags &= ~rpb_gc_active;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case tra_committed:
|
||||
return false;
|
||||
|
||||
case tra_active:
|
||||
if (!(rpb->rpb_flags & rpb_gc_active)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
case tra_precommitted:
|
||||
THREAD_EXIT();
|
||||
THREAD_SLEEP(100); /* milliseconds */
|
||||
THREAD_ENTER();
|
||||
break;
|
||||
|
||||
case tra_limbo:
|
||||
return true;
|
||||
|
||||
case tra_dead:
|
||||
VIO_backout(tdbb, rpb, transaction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void VIO_data(thread_db* tdbb, record_param* rpb, JrdMemoryPool* pool)
|
||||
{
|
||||
/**************************************
|
||||
@ -1804,12 +1695,6 @@ bool VIO_get(thread_db* tdbb, record_param* rpb, RecordSource* rsb, jrd_tra* tra
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
if (rsb && rsb->rsb_flags & rsb_stream_type) {
|
||||
RNG_add_page(rpb->rpb_page);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VIO_DEBUG
|
||||
if (debug_flag > DEBUG_READS_INFO) {
|
||||
printf
|
||||
@ -2486,11 +2371,6 @@ bool VIO_next_record(thread_db* tdbb,
|
||||
return false;
|
||||
} while (!VIO_chase_record_version(tdbb, rpb, rsb, transaction, pool, false));
|
||||
|
||||
#ifdef PC_ENGINE
|
||||
if (rsb && rsb->rsb_flags & rsb_stream_type)
|
||||
RNG_add_page(rpb->rpb_page);
|
||||
#endif
|
||||
|
||||
if (pool) {
|
||||
VIO_data(tdbb, rpb, pool);
|
||||
}
|
||||
|
@ -40,9 +40,6 @@ void VIO_backout(Jrd::thread_db*, Jrd::record_param*, const Jrd::jrd_tra*);
|
||||
void VIO_bump_count(Jrd::thread_db*, USHORT, Jrd::jrd_rel*, bool);
|
||||
bool VIO_chase_record_version(Jrd::thread_db*, Jrd::record_param*, Jrd::RecordSource*,
|
||||
Jrd::jrd_tra*, JrdMemoryPool*, bool);
|
||||
#ifdef PC_ENGINE
|
||||
bool VIO_check_if_updated(Jrd::thread_db*, Jrd::record_param*);
|
||||
#endif
|
||||
void VIO_data(Jrd::thread_db*, Jrd::record_param*, JrdMemoryPool*);
|
||||
void VIO_erase(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*);
|
||||
#ifdef GARBAGE_THREAD
|
||||
|
Loading…
Reference in New Issue
Block a user