mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 23:23:04 +01:00
Wipe out the SCROLLABLE_CURSORS code + minor cleanup.
Also, surfaced scrollability for PSQL cursors (without internal support yet).
This commit is contained in:
parent
136b6013fc
commit
e6909de7f7
@ -729,14 +729,7 @@ USHORT OPT_nav_rsb_size(RecordSource* rsb, USHORT key_length, USHORT size)
|
|||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
DEV_BLKCHK(rsb, type_rsb);
|
DEV_BLKCHK(rsb, type_rsb);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
// allocate extra impure area to hold the current key,
|
|
||||||
// plus an upper and lower bound key value, for a total
|
|
||||||
// of three times the key length for the index
|
|
||||||
size += sizeof(struct irsb_nav) + 3 * key_length;
|
|
||||||
#else
|
|
||||||
size += sizeof(struct irsb_nav) + 2 * key_length;
|
size += sizeof(struct irsb_nav) + 2 * key_length;
|
||||||
#endif
|
|
||||||
size = FB_ALIGN(size, FB_ALIGNMENT);
|
size = FB_ALIGN(size, FB_ALIGNMENT);
|
||||||
// make room for an idx structure to describe the index
|
// make room for an idx structure to describe the index
|
||||||
// that was used to generate this rsb
|
// that was used to generate this rsb
|
||||||
@ -1348,9 +1341,7 @@ RecordSource* OptimizerRetrieval::generateNavigation()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check to see if the fields in the sort match the fields in the index
|
// check to see if the fields in the sort match the fields in the index
|
||||||
// in the exact same order--we used to check for ascending/descending prior
|
// in the exact same order
|
||||||
// to SCROLLABLE_CURSORS, but now descending sorts can use ascending indices
|
|
||||||
// and vice versa.
|
|
||||||
|
|
||||||
bool usableIndex = true;
|
bool usableIndex = true;
|
||||||
index_desc::idx_repeat* idx_tail = idx->idx_rpt;
|
index_desc::idx_repeat* idx_tail = idx->idx_rpt;
|
||||||
|
@ -72,7 +72,7 @@ void WindowRsb::open(thread_db* tdbb)
|
|||||||
SET_TDBB(tdbb);
|
SET_TDBB(tdbb);
|
||||||
|
|
||||||
RSE_open(tdbb, next);
|
RSE_open(tdbb, next);
|
||||||
RSE_internal_get_record(tdbb, next, NULL, RSE_get_forward);
|
RSE_internal_get_record(tdbb, next, NULL);
|
||||||
RSE_close(tdbb, next);
|
RSE_close(tdbb, next);
|
||||||
|
|
||||||
RSE_open(tdbb, next->rsb_next);
|
RSE_open(tdbb, next->rsb_next);
|
||||||
@ -91,7 +91,7 @@ bool WindowRsb::get(thread_db* tdbb)
|
|||||||
{
|
{
|
||||||
SET_TDBB(tdbb);
|
SET_TDBB(tdbb);
|
||||||
|
|
||||||
if (!RSE_internal_get_record(tdbb, next->rsb_next, NULL, RSE_get_forward))
|
if (!RSE_internal_get_record(tdbb, next->rsb_next, NULL))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
jrd_nod* node = (jrd_nod*) next->rsb_arg[0];
|
jrd_nod* node = (jrd_nod*) next->rsb_arg[0];
|
||||||
|
@ -120,9 +120,9 @@
|
|||||||
#define blr_maximum (unsigned char)29
|
#define blr_maximum (unsigned char)29
|
||||||
#define blr_minimum (unsigned char)30
|
#define blr_minimum (unsigned char)30
|
||||||
#define blr_total (unsigned char)31
|
#define blr_total (unsigned char)31
|
||||||
/* count 2
|
|
||||||
#define blr_count2 32
|
// unused codes: 32..33
|
||||||
*/
|
|
||||||
#define blr_add (unsigned char)34
|
#define blr_add (unsigned char)34
|
||||||
#define blr_subtract (unsigned char)35
|
#define blr_subtract (unsigned char)35
|
||||||
#define blr_multiply (unsigned char)36
|
#define blr_multiply (unsigned char)36
|
||||||
@ -133,7 +133,6 @@
|
|||||||
#define blr_parameter2 (unsigned char)41
|
#define blr_parameter2 (unsigned char)41
|
||||||
#define blr_from (unsigned char)42
|
#define blr_from (unsigned char)42
|
||||||
#define blr_via (unsigned char)43
|
#define blr_via (unsigned char)43
|
||||||
#define blr_parameter2_old (unsigned char)44 /* Confusion */
|
|
||||||
#define blr_user_name (unsigned char)44 /* added from gds.h */
|
#define blr_user_name (unsigned char)44 /* added from gds.h */
|
||||||
#define blr_null (unsigned char)45
|
#define blr_null (unsigned char)45
|
||||||
|
|
||||||
@ -156,8 +155,7 @@
|
|||||||
#define blr_unique (unsigned char)62
|
#define blr_unique (unsigned char)62
|
||||||
#define blr_like (unsigned char)63
|
#define blr_like (unsigned char)63
|
||||||
|
|
||||||
//#define blr_stream (unsigned char)65
|
// unused codes: 64..66
|
||||||
//#define blr_set_index (unsigned char)66
|
|
||||||
|
|
||||||
#define blr_rse (unsigned char)67
|
#define blr_rse (unsigned char)67
|
||||||
#define blr_first (unsigned char)68
|
#define blr_first (unsigned char)68
|
||||||
@ -174,6 +172,8 @@
|
|||||||
#define blr_aggregate (unsigned char)79
|
#define blr_aggregate (unsigned char)79
|
||||||
#define blr_join_type (unsigned char)80
|
#define blr_join_type (unsigned char)80
|
||||||
|
|
||||||
|
// unused codes: 81..82
|
||||||
|
|
||||||
#define blr_agg_count (unsigned char)83
|
#define blr_agg_count (unsigned char)83
|
||||||
#define blr_agg_max (unsigned char)84
|
#define blr_agg_max (unsigned char)84
|
||||||
#define blr_agg_min (unsigned char)85
|
#define blr_agg_min (unsigned char)85
|
||||||
@ -189,6 +189,8 @@
|
|||||||
#define blr_agg_total_distinct (unsigned char)95
|
#define blr_agg_total_distinct (unsigned char)95
|
||||||
#define blr_agg_average_distinct (unsigned char)96
|
#define blr_agg_average_distinct (unsigned char)96
|
||||||
|
|
||||||
|
// unused codes: 97..99
|
||||||
|
|
||||||
#define blr_function (unsigned char)100
|
#define blr_function (unsigned char)100
|
||||||
#define blr_gen_id (unsigned char)101
|
#define blr_gen_id (unsigned char)101
|
||||||
#define blr_prot_mask (unsigned char)102
|
#define blr_prot_mask (unsigned char)102
|
||||||
@ -198,31 +200,16 @@
|
|||||||
#define blr_matching2 (unsigned char)106
|
#define blr_matching2 (unsigned char)106
|
||||||
#define blr_index (unsigned char)107
|
#define blr_index (unsigned char)107
|
||||||
#define blr_ansi_like (unsigned char)108
|
#define blr_ansi_like (unsigned char)108
|
||||||
//#define blr_bookmark (unsigned char)109
|
#define blr_scrollable (unsigned char) 109
|
||||||
//#define blr_crack (unsigned char)110
|
|
||||||
//#define blr_force_crack (unsigned char)111
|
|
||||||
#define blr_seek (unsigned char)112
|
|
||||||
//#define blr_find (unsigned char)113
|
|
||||||
|
|
||||||
/* these indicate directions for blr_seek and blr_find */
|
// unused codes: 110..117
|
||||||
|
|
||||||
#define blr_continue (unsigned char)0
|
|
||||||
#define blr_forward (unsigned char)1
|
|
||||||
#define blr_backward (unsigned char)2
|
|
||||||
#define blr_bof_forward (unsigned char)3
|
|
||||||
#define blr_eof_backward (unsigned char)4
|
|
||||||
|
|
||||||
//#define blr_lock_relation (unsigned char)114
|
|
||||||
//#define blr_lock_record (unsigned char)115
|
|
||||||
//#define blr_set_bookmark (unsigned char)116
|
|
||||||
//#define blr_get_bookmark (unsigned char)117
|
|
||||||
|
|
||||||
#define blr_run_count (unsigned char)118 /* changed from 88 to avoid conflict with blr_parameter3 */
|
#define blr_run_count (unsigned char)118 /* changed from 88 to avoid conflict with blr_parameter3 */
|
||||||
#define blr_rs_stream (unsigned char)119
|
#define blr_rs_stream (unsigned char)119
|
||||||
#define blr_exec_proc (unsigned char)120
|
#define blr_exec_proc (unsigned char)120
|
||||||
//#define blr_begin_range (unsigned char)121
|
|
||||||
//#define blr_end_range (unsigned char)122
|
// unused codes: 121..123
|
||||||
//#define blr_delete_range (unsigned char)123
|
|
||||||
#define blr_procedure (unsigned char)124
|
#define blr_procedure (unsigned char)124
|
||||||
#define blr_pid (unsigned char)125
|
#define blr_pid (unsigned char)125
|
||||||
#define blr_exec_pid (unsigned char)126
|
#define blr_exec_pid (unsigned char)126
|
||||||
@ -232,13 +219,13 @@
|
|||||||
#define blr_error_handler (unsigned char)130
|
#define blr_error_handler (unsigned char)130
|
||||||
|
|
||||||
#define blr_cast (unsigned char)131
|
#define blr_cast (unsigned char)131
|
||||||
//#define blr_release_lock (unsigned char)132
|
|
||||||
//#define blr_release_locks (unsigned char)133
|
// unused codes: 132..133
|
||||||
|
|
||||||
#define blr_start_savepoint (unsigned char)134
|
#define blr_start_savepoint (unsigned char)134
|
||||||
#define blr_end_savepoint (unsigned char)135
|
#define blr_end_savepoint (unsigned char)135
|
||||||
//#define blr_find_dbkey (unsigned char)136
|
|
||||||
//#define blr_range_relation (unsigned char)137
|
// unused codes: 136..138
|
||||||
//#define blr_delete_ranges (unsigned char)138
|
|
||||||
|
|
||||||
#define blr_plan (unsigned char)139 /* access plan items */
|
#define blr_plan (unsigned char)139 /* access plan items */
|
||||||
#define blr_merge (unsigned char)140
|
#define blr_merge (unsigned char)140
|
||||||
@ -250,20 +237,21 @@
|
|||||||
|
|
||||||
#define blr_relation2 (unsigned char)146
|
#define blr_relation2 (unsigned char)146
|
||||||
#define blr_rid2 (unsigned char)147
|
#define blr_rid2 (unsigned char)147
|
||||||
//#define blr_reset_stream (unsigned char)148
|
|
||||||
//#define blr_release_bookmark (unsigned char)149
|
// unused codes: 148..149
|
||||||
|
|
||||||
#define blr_set_generator (unsigned char)150
|
#define blr_set_generator (unsigned char)150
|
||||||
|
|
||||||
#define blr_ansi_any (unsigned char)151 /* required for NULL handling */
|
#define blr_ansi_any (unsigned char)151 /* required for NULL handling */
|
||||||
#define blr_exists (unsigned char)152 /* required for NULL handling */
|
#define blr_exists (unsigned char)152 /* required for NULL handling */
|
||||||
//#define blr_cardinality (unsigned char)153
|
|
||||||
|
// unused codes: 153
|
||||||
|
|
||||||
#define blr_record_version (unsigned char)154 /* get tid of record */
|
#define blr_record_version (unsigned char)154 /* get tid of record */
|
||||||
#define blr_stall (unsigned char)155 /* fake server stall */
|
#define blr_stall (unsigned char)155 /* fake server stall */
|
||||||
|
|
||||||
//#define blr_seek_no_warn (unsigned char)156
|
// unused codes: 156..157
|
||||||
//#define blr_find_dbkey_version (unsigned char)157 /* find dbkey with record version */
|
|
||||||
#define blr_ansi_all (unsigned char)158 /* required for NULL handling */
|
#define blr_ansi_all (unsigned char)158 /* required for NULL handling */
|
||||||
|
|
||||||
#define blr_extract (unsigned char)159
|
#define blr_extract (unsigned char)159
|
||||||
@ -298,6 +286,8 @@
|
|||||||
#define blr_agg_list_distinct (unsigned char)171
|
#define blr_agg_list_distinct (unsigned char)171
|
||||||
#define blr_modify2 (unsigned char)172
|
#define blr_modify2 (unsigned char)172
|
||||||
|
|
||||||
|
// unused codes: 173
|
||||||
|
|
||||||
/* FB 1.0 specific BLR */
|
/* FB 1.0 specific BLR */
|
||||||
|
|
||||||
#define blr_current_role (unsigned char)174
|
#define blr_current_role (unsigned char)174
|
||||||
@ -344,6 +334,16 @@
|
|||||||
#define blr_cursor_open (unsigned char)0
|
#define blr_cursor_open (unsigned char)0
|
||||||
#define blr_cursor_close (unsigned char)1
|
#define blr_cursor_close (unsigned char)1
|
||||||
#define blr_cursor_fetch (unsigned char)2
|
#define blr_cursor_fetch (unsigned char)2
|
||||||
|
#define blr_cursor_fetch_scroll (unsigned char)3
|
||||||
|
|
||||||
|
/* scroll options */
|
||||||
|
|
||||||
|
#define blr_scroll_forward (unsigned char)0
|
||||||
|
#define blr_scroll_backward (unsigned char)1
|
||||||
|
#define blr_scroll_bof (unsigned char)2
|
||||||
|
#define blr_scroll_eof (unsigned char)3
|
||||||
|
#define blr_scroll_absolute (unsigned char)4
|
||||||
|
#define blr_scroll_relative (unsigned char)5
|
||||||
|
|
||||||
/* FB 2.1 specific BLR */
|
/* FB 2.1 specific BLR */
|
||||||
|
|
||||||
|
@ -400,46 +400,6 @@ bool keyEquality(USHORT length, const UCHAR* data, const IndexNode* indexNode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
UCHAR* lastNode(btree_page* page, exp_index_buf* expanded_page, btree_exp** expanded_node)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* l a s t N o d e
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Find the last node on a page. Used when walking
|
|
||||||
* down the right side of an index tree.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
|
|
||||||
// the last expanded node is always at the end of the page
|
|
||||||
// minus the size of a btree_exp, since there is always an extra
|
|
||||||
// btree_exp node with zero-length tail at the end of the page
|
|
||||||
btree_exp* enode = (btree_exp*) ((UCHAR*) expanded_page + expanded_page->exp_length - BTX_SIZE);
|
|
||||||
|
|
||||||
// starting at the end of the page, find the
|
|
||||||
// first node that is not an end marker
|
|
||||||
UCHAR* pointer = ((UCHAR*) page + page->btr_length);
|
|
||||||
const UCHAR flags = page->btr_header.pag_flags;
|
|
||||||
IndexNode node;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
pointer = previousNode(/*&node,*/ pointer, /*flags,*/ &enode);
|
|
||||||
if (!node.isEndBucket && !node.isEndLevel)
|
|
||||||
{
|
|
||||||
if (expanded_node) {
|
|
||||||
*expanded_node = enode;
|
|
||||||
}
|
|
||||||
return node.nodePointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
UCHAR* nextNode(IndexNode* node, UCHAR* pointer,
|
UCHAR* nextNode(IndexNode* node, UCHAR* pointer,
|
||||||
UCHAR flags, btree_exp** expanded_node)
|
UCHAR flags, btree_exp** expanded_node)
|
||||||
{
|
{
|
||||||
@ -467,31 +427,6 @@ UCHAR* nextNode(IndexNode* node, UCHAR* pointer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
UCHAR* previousNode(/*IndexNode* node,*/ UCHAR* pointer,
|
|
||||||
/*UCHAR flags,*/ btree_exp** expanded_node)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* p r e v i o u s N o d e
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Find the previous node on a page. Used when walking
|
|
||||||
* an index backwards.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
|
|
||||||
pointer = (pointer - (*expanded_node)->btx_btr_previous_length);
|
|
||||||
|
|
||||||
*expanded_node = (btree_exp*) ((UCHAR*) *expanded_node - (*expanded_node)->btx_previous_length);
|
|
||||||
|
|
||||||
return pointer;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
UCHAR* readJumpInfo(IndexJumpInfo* jumpInfo, UCHAR* pagePointer)
|
UCHAR* readJumpInfo(IndexJumpInfo* jumpInfo, UCHAR* pagePointer)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
|
@ -87,16 +87,8 @@ namespace BTreeNode {
|
|||||||
|
|
||||||
bool keyEquality(USHORT length, const UCHAR* data, const Ods::IndexNode* indexNode);
|
bool keyEquality(USHORT length, const UCHAR* data, const Ods::IndexNode* indexNode);
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
UCHAR* lastNode(Ods::btree_page* page, exp_index_buf* expanded_page, btree_exp** expanded_node);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UCHAR* nextNode(Ods::IndexNode* node, UCHAR* pointer,
|
UCHAR* nextNode(Ods::IndexNode* node, UCHAR* pointer,
|
||||||
UCHAR flags, btree_exp** expanded_node);
|
UCHAR flags, btree_exp** expanded_node);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
UCHAR* previousNode(/*Ods::IndexNode* node,*/ UCHAR* pointer,
|
|
||||||
/*UCHAR flags,*/ btree_exp** expanded_node);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//void quad_put(SLONG value, UCHAR *data);
|
//void quad_put(SLONG value, UCHAR *data);
|
||||||
|
|
||||||
|
159
src/jrd/btr.cpp
159
src/jrd/btr.cpp
@ -638,11 +638,7 @@ void BTR_evaluate(thread_db* tdbb, IndexRetrieval* retrieval, RecordBitmap** bit
|
|||||||
lower.key_length = 0;
|
lower.key_length = 0;
|
||||||
upper.key_flags = 0;
|
upper.key_flags = 0;
|
||||||
upper.key_length = 0;
|
upper.key_length = 0;
|
||||||
btree_page* page = BTR_find_page(tdbb, retrieval, &window, &idx, &lower, &upper
|
btree_page* page = BTR_find_page(tdbb, retrieval, &window, &idx, &lower, &upper);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, false
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
const bool descending = (idx.idx_flags & idx_descending);
|
const bool descending = (idx.idx_flags & idx_descending);
|
||||||
bool skipLowerKey = (retrieval->irb_generic & irb_exclude_lower);
|
bool skipLowerKey = (retrieval->irb_generic & irb_exclude_lower);
|
||||||
@ -812,12 +808,7 @@ btree_page* BTR_find_page(thread_db* tdbb,
|
|||||||
WIN* window,
|
WIN* window,
|
||||||
index_desc* idx,
|
index_desc* idx,
|
||||||
temporary_key* lower,
|
temporary_key* lower,
|
||||||
temporary_key* upper
|
temporary_key* upper)
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
,
|
|
||||||
const bool backwards
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -890,13 +881,8 @@ btree_page* BTR_find_page(thread_db* tdbb,
|
|||||||
const bool ignoreNulls = ((idx->idx_count == 1) && !(idx->idx_flags & idx_descending) &&
|
const bool ignoreNulls = ((idx->idx_count == 1) && !(idx->idx_flags & idx_descending) &&
|
||||||
(retrieval->irb_generic & irb_ignore_null_value_key) && !(retrieval->irb_lower_count));
|
(retrieval->irb_generic & irb_ignore_null_value_key) && !(retrieval->irb_lower_count));
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
const bool firstData =
|
|
||||||
((!backwards && retrieval->irb_lower_count) || (!backwards && ignoreNulls) ||
|
|
||||||
(backwards && retrieval->irb_upper_count));
|
|
||||||
#else
|
|
||||||
const bool firstData = (retrieval->irb_lower_count || ignoreNulls);
|
const bool firstData = (retrieval->irb_lower_count || ignoreNulls);
|
||||||
#endif
|
|
||||||
if (firstData)
|
if (firstData)
|
||||||
{
|
{
|
||||||
// Make a temporary key with length 1 and zero byte, this will return
|
// Make a temporary key with length 1 and zero byte, this will return
|
||||||
@ -910,12 +896,7 @@ btree_page* BTR_find_page(thread_db* tdbb,
|
|||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
const temporary_key* tkey =
|
|
||||||
backwards ? upper : (ignoreNulls ? &firstNotNullKey : lower);
|
|
||||||
#else
|
|
||||||
const temporary_key* tkey = ignoreNulls ? &firstNotNullKey : lower;
|
const temporary_key* tkey = ignoreNulls ? &firstNotNullKey : lower;
|
||||||
#endif
|
|
||||||
const SLONG number = find_page(page, tkey, idx->idx_flags,
|
const SLONG number = find_page(page, tkey, idx->idx_flags,
|
||||||
NO_VALUE, (retrieval->irb_generic & (irb_starting | irb_partial)));
|
NO_VALUE, (retrieval->irb_generic & (irb_starting | irb_partial)));
|
||||||
if (number != END_BUCKET)
|
if (number != END_BUCKET)
|
||||||
@ -935,36 +916,13 @@ btree_page* BTR_find_page(thread_db* tdbb,
|
|||||||
{
|
{
|
||||||
UCHAR* pointer;
|
UCHAR* pointer;
|
||||||
const UCHAR* const endPointer = (UCHAR*) page + page->btr_length;
|
const UCHAR* const endPointer = (UCHAR*) page + page->btr_length;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
pointer = BTreeNode::getPointerFirstNode(page);
|
||||||
if (backwards) {
|
|
||||||
pointer = BTR_last_node(page, NAV_expand_index(window, 0), 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
pointer = BTreeNode::getPointerFirstNode(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer = BTreeNode::readNode(&node, pointer, page->btr_header.pag_flags, false);
|
pointer = BTreeNode::readNode(&node, pointer, page->btr_header.pag_flags, false);
|
||||||
// Check if pointer is still valid
|
// Check if pointer is still valid
|
||||||
if (pointer > endPointer) {
|
if (pointer > endPointer) {
|
||||||
BUGCHECK(204); // msg 204 index inconsistent
|
BUGCHECK(204); // msg 204 index inconsistent
|
||||||
}
|
}
|
||||||
page = (btree_page*) CCH_HANDOFF(tdbb, window, node.pageNumber, LCK_read, pag_index);
|
page = (btree_page*) CCH_HANDOFF(tdbb, window, node.pageNumber, LCK_read, pag_index);
|
||||||
|
|
||||||
// make sure that we are actually on the last page on this
|
|
||||||
// level when scanning in the backward direction
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (backwards)
|
|
||||||
{
|
|
||||||
while (page->btr_sibling)
|
|
||||||
{
|
|
||||||
page = (btree_page*) CCH_HANDOFF(tdbb, window, page->btr_sibling,
|
|
||||||
LCK_read, pag_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1412,109 +1370,6 @@ USHORT BTR_key_length(thread_db* tdbb, jrd_rel* relation, index_desc* idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
UCHAR* BTR_last_node(btree_page* page, exp_index_buf* expanded_page, btree_exp** expanded_node)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* B T R _ l a s t _ n o d e
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Find the last node on a page. Used when walking
|
|
||||||
* down the right side of an index tree.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
|
|
||||||
// the last expanded node is always at the end of the page
|
|
||||||
// minus the size of a btree_exp, since there is always an extra
|
|
||||||
// btree_exp node with zero-length tail at the end of the page
|
|
||||||
btree_exp* enode = (btree_exp*) ((UCHAR*)expanded_page + expanded_page->exp_length - BTX_SIZE);
|
|
||||||
|
|
||||||
// starting at the end of the page, find the
|
|
||||||
// first node that is not an end marker
|
|
||||||
UCHAR* pointer = ((UCHAR*)page + page->btr_length);
|
|
||||||
const UCHAR flags = page->btr_header.pag_flags;
|
|
||||||
IndexNode node;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
pointer = BTreeNode::previousNode(/*&node,*/ pointer, /*flags,*/ &enode);
|
|
||||||
if (!node.isEndBucket && !node.isEndLevel)
|
|
||||||
{
|
|
||||||
if (expanded_node) {
|
|
||||||
*expanded_node = enode;
|
|
||||||
}
|
|
||||||
return node.nodePointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
btree_page* BTR_left_handoff(thread_db* tdbb, WIN* window, btree_page* page, SSHORT lock_level)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* B T R _ l e f t _ h a n d o f f
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Handoff a btree page to the left. This is more difficult than a
|
|
||||||
* right handoff because we have to traverse pages without handing
|
|
||||||
* off locks. (A lock handoff to the left while someone was handing
|
|
||||||
* off to the right could result in deadlock.)
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
|
|
||||||
SET_TDBB(tdbb);
|
|
||||||
const Database* dbb = tdbb->getDatabase();
|
|
||||||
CHECK_DBB(dbb);
|
|
||||||
|
|
||||||
const PageNumber original_page(window->win_page);
|
|
||||||
const SLONG left_sibling = page->btr_left_sibling;
|
|
||||||
|
|
||||||
CCH_RELEASE(tdbb, window);
|
|
||||||
window->win_page = left_sibling;
|
|
||||||
page = (btree_page*) CCH_FETCH(tdbb, window, lock_level, pag_index);
|
|
||||||
|
|
||||||
SLONG sibling = page->btr_sibling;
|
|
||||||
if (sibling == original_page) {
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we are not handing off pages, a page could split before we get to it.
|
|
||||||
// To detect this case, fetch the left sibling pointer and then handoff right
|
|
||||||
// sibling pointers until we reach the page to the left of the page passed
|
|
||||||
// to us.
|
|
||||||
|
|
||||||
while (sibling != original_page)
|
|
||||||
{
|
|
||||||
page = (btree_page*) CCH_HANDOFF(tdbb, window, page->btr_sibling, lock_level, pag_index);
|
|
||||||
sibling = page->btr_sibling;
|
|
||||||
}
|
|
||||||
WIN fix_win(original_page);
|
|
||||||
btree_page* fix_page = (btree_page*) CCH_FETCH(tdbb, &fix_win, LCK_write, pag_index);
|
|
||||||
|
|
||||||
// if someone else already fixed it, just return
|
|
||||||
if (fix_page->btr_left_sibling == window->win_page)
|
|
||||||
{
|
|
||||||
CCH_RELEASE(tdbb, &fix_win);
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
CCH_MARK(tdbb, &fix_win);
|
|
||||||
fix_page->btr_left_sibling = window->win_page;
|
|
||||||
|
|
||||||
CCH_RELEASE(tdbb, &fix_win);
|
|
||||||
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
USHORT BTR_lookup(thread_db* tdbb, jrd_rel* relation, USHORT id, index_desc* buffer,
|
USHORT BTR_lookup(thread_db* tdbb, jrd_rel* relation, USHORT id, index_desc* buffer,
|
||||||
RelationPages* relPages)
|
RelationPages* relPages)
|
||||||
{
|
{
|
||||||
@ -3446,11 +3301,7 @@ static SLONG fast_load(thread_db* tdbb,
|
|||||||
// Get the next record in sorted order.
|
// Get the next record in sorted order.
|
||||||
|
|
||||||
UCHAR* record;
|
UCHAR* record;
|
||||||
SORT_get(tdbb, sort_handle, reinterpret_cast<ULONG**>(&record)
|
SORT_get(tdbb, sort_handle, reinterpret_cast<ULONG**>(&record));
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, RSE_get_forward
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!record) {
|
if (!record) {
|
||||||
break;
|
break;
|
||||||
|
@ -41,13 +41,8 @@ bool BTR_description(Jrd::thread_db*, Jrd::jrd_rel*, Ods::index_root_page*, Jrd:
|
|||||||
DSC* BTR_eval_expression(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*, bool&);
|
DSC* BTR_eval_expression(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*, bool&);
|
||||||
void BTR_evaluate(Jrd::thread_db*, Jrd::IndexRetrieval*, Jrd::RecordBitmap**, Jrd::RecordBitmap*);
|
void BTR_evaluate(Jrd::thread_db*, Jrd::IndexRetrieval*, Jrd::RecordBitmap**, Jrd::RecordBitmap*);
|
||||||
UCHAR* BTR_find_leaf(Ods::btree_page*, Jrd::temporary_key*, UCHAR*, USHORT*, bool, bool);
|
UCHAR* BTR_find_leaf(Ods::btree_page*, Jrd::temporary_key*, UCHAR*, USHORT*, bool, bool);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
Ods::btree_page* BTR_find_page(Jrd::thread_db*, Jrd::IndexRetrieval*, Jrd::win*, Jrd::index_desc*,
|
|
||||||
Jrd::temporary_key*, Jrd::temporary_key*, const bool);
|
|
||||||
#else
|
|
||||||
Ods::btree_page* BTR_find_page(Jrd::thread_db*, Jrd::IndexRetrieval*, Jrd::win*, Jrd::index_desc*,
|
Ods::btree_page* BTR_find_page(Jrd::thread_db*, Jrd::IndexRetrieval*, Jrd::win*, Jrd::index_desc*,
|
||||||
Jrd::temporary_key*, Jrd::temporary_key*);
|
Jrd::temporary_key*, Jrd::temporary_key*);
|
||||||
#endif
|
|
||||||
void BTR_insert(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*);
|
void BTR_insert(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*);
|
||||||
Jrd::idx_e BTR_key(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::Record*, Jrd::index_desc*, Jrd::temporary_key*,
|
Jrd::idx_e BTR_key(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::Record*, Jrd::index_desc*, Jrd::temporary_key*,
|
||||||
Jrd::idx_null_state*, const bool);
|
Jrd::idx_null_state*, const bool);
|
||||||
|
@ -998,9 +998,6 @@ void CMP_get_desc(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node, DSC* des
|
|||||||
case nod_count:
|
case nod_count:
|
||||||
case nod_gen_id:
|
case nod_gen_id:
|
||||||
case nod_lock_state:
|
case nod_lock_state:
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
case nod_seek:
|
|
||||||
#endif
|
|
||||||
desc->dsc_dtype = dtype_long;
|
desc->dsc_dtype = dtype_long;
|
||||||
desc->dsc_length = sizeof(SLONG);
|
desc->dsc_length = sizeof(SLONG);
|
||||||
desc->dsc_scale = 0;
|
desc->dsc_scale = 0;
|
||||||
@ -2191,10 +2188,6 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb, bool internal_f
|
|||||||
request->req_flags |= req_blr_version4;
|
request->req_flags |= req_blr_version4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
request->req_async_message = csb->csb_async_message;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Take out existence locks on resources used in request. This is
|
// Take out existence locks on resources used in request. This is
|
||||||
// a little complicated since relation locks MUST be taken before
|
// a little complicated since relation locks MUST be taken before
|
||||||
// index locks.
|
// index locks.
|
||||||
@ -4042,10 +4035,9 @@ jrd_nod* CMP_pass1(thread_db* tdbb, CompilerScratch* csb, jrd_nod* node)
|
|||||||
return (jrd_nod*) pass1_rse(tdbb, csb, (RecordSelExpr*) node);
|
return (jrd_nod*) pass1_rse(tdbb, csb, (RecordSelExpr*) node);
|
||||||
|
|
||||||
case nod_cursor_stmt:
|
case nod_cursor_stmt:
|
||||||
if ((UCHAR) (IPTR) node->nod_arg[e_cursor_stmt_op] == blr_cursor_fetch) {
|
node->nod_arg[e_cursor_stmt_scroll_op] = CMP_pass1(tdbb, csb, node->nod_arg[e_cursor_stmt_scroll_op]);
|
||||||
node->nod_arg[e_cursor_stmt_seek] = CMP_pass1(tdbb, csb, node->nod_arg[e_cursor_stmt_seek]);
|
node->nod_arg[e_cursor_stmt_scroll_val] = CMP_pass1(tdbb, csb, node->nod_arg[e_cursor_stmt_scroll_val]);
|
||||||
node->nod_arg[e_cursor_stmt_into] = CMP_pass1(tdbb, csb, node->nod_arg[e_cursor_stmt_into]);
|
node->nod_arg[e_cursor_stmt_into] = CMP_pass1(tdbb, csb, node->nod_arg[e_cursor_stmt_into]);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nod_max:
|
case nod_max:
|
||||||
@ -4689,9 +4681,6 @@ static RecordSelExpr* pass1_rse(thread_db* tdbb,
|
|||||||
jrd_nod* skip = rse->rse_skip;
|
jrd_nod* skip = rse->rse_skip;
|
||||||
jrd_nod* plan = rse->rse_plan;
|
jrd_nod* plan = rse->rse_plan;
|
||||||
const bool writelock = rse->rse_writelock;
|
const bool writelock = rse->rse_writelock;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
jrd_nod* async_message = rse->rse_async_message;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// zip thru RecordSelExpr expanding views and inner joins
|
// zip thru RecordSelExpr expanding views and inner joins
|
||||||
jrd_nod** arg = rse->rse_relation;
|
jrd_nod** arg = rse->rse_relation;
|
||||||
@ -4765,13 +4754,6 @@ static RecordSelExpr* pass1_rse(thread_db* tdbb,
|
|||||||
|
|
||||||
rse->rse_writelock = writelock;
|
rse->rse_writelock = writelock;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (async_message) {
|
|
||||||
rse->rse_async_message = CMP_pass1(tdbb, csb, async_message);
|
|
||||||
csb->csb_async_message = rse->rse_async_message;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// we are no longer in the scope of this RecordSelExpr
|
// we are no longer in the scope of this RecordSelExpr
|
||||||
|
|
||||||
csb->csb_current_nodes.pop();
|
csb->csb_current_nodes.pop();
|
||||||
@ -5289,33 +5271,19 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
|
|||||||
case nod_for:
|
case nod_for:
|
||||||
rse_node = node->nod_arg[e_for_re];
|
rse_node = node->nod_arg[e_for_re];
|
||||||
rsb_ptr = (RecordSource**) & node->nod_arg[e_for_rsb];
|
rsb_ptr = (RecordSource**) & node->nod_arg[e_for_rsb];
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
csb->csb_current_rse = rse_node;
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nod_dcl_cursor:
|
case nod_dcl_cursor:
|
||||||
rse_node = node->nod_arg[e_dcl_cursor_rse];
|
rse_node = node->nod_arg[e_dcl_cursor_rse];
|
||||||
rsb_ptr = (RecordSource**) & node->nod_arg[e_dcl_cursor_rsb];
|
rsb_ptr = (RecordSource**) & node->nod_arg[e_dcl_cursor_rsb];
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
csb->csb_current_rse = rse_node;
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nod_cursor_stmt:
|
case nod_cursor_stmt:
|
||||||
if ((UCHAR) (IPTR) node->nod_arg[e_cursor_stmt_op] == blr_cursor_fetch) {
|
CMP_pass2(tdbb, csb, node->nod_arg[e_cursor_stmt_scroll_op], node);
|
||||||
CMP_pass2(tdbb, csb, node->nod_arg[e_cursor_stmt_seek], node);
|
CMP_pass2(tdbb, csb, node->nod_arg[e_cursor_stmt_scroll_val], node);
|
||||||
CMP_pass2(tdbb, csb, node->nod_arg[e_cursor_stmt_into], node);
|
CMP_pass2(tdbb, csb, node->nod_arg[e_cursor_stmt_into], node);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
case nod_seek:
|
|
||||||
// store the RecordSelExpr in whose scope we are defined
|
|
||||||
node->nod_arg[e_seek_rse] = (jrd_nod*) csb->csb_current_rse;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case nod_max:
|
case nod_max:
|
||||||
case nod_min:
|
case nod_min:
|
||||||
case nod_count:
|
case nod_count:
|
||||||
@ -5598,9 +5566,6 @@ jrd_nod* CMP_pass2(thread_db* tdbb, CompilerScratch* csb, jrd_nod* const node, j
|
|||||||
case nod_current_timestamp:
|
case nod_current_timestamp:
|
||||||
case nod_current_date:
|
case nod_current_date:
|
||||||
case nod_derived_expr:
|
case nod_derived_expr:
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
case nod_seek:
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
dsc descriptor_a;
|
dsc descriptor_a;
|
||||||
CMP_get_desc(tdbb, csb, node, &descriptor_a);
|
CMP_get_desc(tdbb, csb, node, &descriptor_a);
|
||||||
@ -5846,11 +5811,6 @@ static void pass2_rse(thread_db* tdbb, CompilerScratch* csb, RecordSelExpr* rse)
|
|||||||
plan_check(csb, rse);
|
plan_check(csb, rse);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (rse->rse_async_message) {
|
|
||||||
CMP_pass2(tdbb, csb, rse->rse_async_message, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
csb->csb_current_nodes.pop();
|
csb->csb_current_nodes.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6193,6 +6153,10 @@ static RecordSource* post_rse(thread_db* tdbb, CompilerScratch* csb, RecordSelEx
|
|||||||
rsb->rsb_flags |= rsb_singular;
|
rsb->rsb_flags |= rsb_singular;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rse->nod_flags & rse_scrollable) {
|
||||||
|
rsb->rsb_flags |= rsb_scrollable;
|
||||||
|
}
|
||||||
|
|
||||||
// mark all the substreams as inactive
|
// mark all the substreams as inactive
|
||||||
|
|
||||||
jrd_nod** ptr = rse->rse_relation;
|
jrd_nod** ptr = rse->rse_relation;
|
||||||
@ -6212,9 +6176,6 @@ static RecordSource* post_rse(thread_db* tdbb, CompilerScratch* csb, RecordSelEx
|
|||||||
}
|
}
|
||||||
|
|
||||||
csb->csb_fors.push(rsb);
|
csb->csb_fors.push(rsb);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
rse->rse_rsb = rsb;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return rsb;
|
return rsb;
|
||||||
}
|
}
|
||||||
|
@ -1530,9 +1530,6 @@ punt:
|
|||||||
bool DPM_next(thread_db* tdbb,
|
bool DPM_next(thread_db* tdbb,
|
||||||
record_param* rpb,
|
record_param* rpb,
|
||||||
USHORT lock_type,
|
USHORT lock_type,
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
bool backwards,
|
|
||||||
#endif
|
|
||||||
bool onepage)
|
bool onepage)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -1570,40 +1567,7 @@ bool DPM_next(thread_db* tdbb,
|
|||||||
|
|
||||||
// Find starting point
|
// Find starting point
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
rpb->rpb_number.increment();
|
||||||
if (backwards)
|
|
||||||
{
|
|
||||||
if (rpb->rpb_number.isEmpty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!rpb->rpb_number.isBof()) {
|
|
||||||
rpb->rpb_number.decrement();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* if the stream was just opened, assume we want to start
|
|
||||||
at the end of the stream, so compute the last theoretically
|
|
||||||
possible rpb_number and go down from there.
|
|
||||||
For now, we must force a scan to make sure that we get
|
|
||||||
the last pointer page: this should be changed to use
|
|
||||||
a coordination mechanism (probably using a shared lock)
|
|
||||||
to keep apprised of when a pointer page gets added */
|
|
||||||
|
|
||||||
DPM_scan_pages(tdbb);
|
|
||||||
const vcl* vector = relPages->rel_pages;
|
|
||||||
if (!vector) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const size_t pp_sequence = vector->count();
|
|
||||||
rpb->rpb_number.setValue(
|
|
||||||
((SINT64) pp_sequence) * dbb->dbb_dp_per_pp * dbb->dbb_max_records - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
rpb->rpb_number.increment();
|
|
||||||
}
|
|
||||||
|
|
||||||
SSHORT slot, line;
|
SSHORT slot, line;
|
||||||
USHORT pp_sequence;
|
USHORT pp_sequence;
|
||||||
@ -1625,12 +1589,6 @@ bool DPM_next(thread_db* tdbb,
|
|||||||
BUGCHECK(249); // msg 249 pointer page vanished from DPM_next
|
BUGCHECK(249); // msg 249 pointer page vanished from DPM_next
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (backwards && slot >= ppage->ppg_count) {
|
|
||||||
slot = ppage->ppg_count - 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (; slot >= 0 && slot < ppage->ppg_count;)
|
for (; slot >= 0 && slot < ppage->ppg_count;)
|
||||||
{
|
{
|
||||||
const SLONG page_number = ppage->ppg_page[slot];
|
const SLONG page_number = ppage->ppg_page[slot];
|
||||||
@ -1640,11 +1598,7 @@ bool DPM_next(thread_db* tdbb,
|
|||||||
// Perform sequential prefetch of relation's data pages.
|
// Perform sequential prefetch of relation's data pages.
|
||||||
// This may need more work for scrollable cursors.
|
// This may need more work for scrollable cursors.
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (!onepage && !line && !backwards)
|
|
||||||
#else
|
|
||||||
if (!onepage && !line)
|
if (!onepage && !line)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
if (!(slot % dbb->dbb_prefetch_sequence))
|
if (!(slot % dbb->dbb_prefetch_sequence))
|
||||||
{
|
{
|
||||||
@ -1669,19 +1623,7 @@ bool DPM_next(thread_db* tdbb,
|
|||||||
const data_page* dpage = (data_page*) CCH_HANDOFF(tdbb, window,
|
const data_page* dpage = (data_page*) CCH_HANDOFF(tdbb, window,
|
||||||
page_number, lock_type, pag_data);
|
page_number, lock_type, pag_data);
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
for (; line >= 0 && line < dpage->dpg_count; ++line)
|
||||||
if (backwards && line >= dpage->dpg_count) {
|
|
||||||
line = dpage->dpg_count - 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (; line >= 0 && line < dpage->dpg_count;
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
backwards ? line-- : line++
|
|
||||||
#else
|
|
||||||
++line
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
if (get_header(window, line, rpb) &&
|
if (get_header(window, line, rpb) &&
|
||||||
!(rpb->rpb_flags & (rpb_blob | rpb_chained | rpb_fragment)))
|
!(rpb->rpb_flags & (rpb_blob | rpb_chained | rpb_fragment)))
|
||||||
@ -1725,35 +1667,14 @@ bool DPM_next(thread_db* tdbb,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
slot++;
|
||||||
if (backwards)
|
line = 0;
|
||||||
{
|
|
||||||
slot--;
|
|
||||||
line = dbb->dbb_max_records - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
slot++;
|
|
||||||
line = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const UCHAR flags = ppage->ppg_header.pag_flags;
|
const UCHAR flags = ppage->ppg_header.pag_flags;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
pp_sequence++;
|
||||||
if (backwards)
|
slot = 0;
|
||||||
{
|
line = 0;
|
||||||
pp_sequence--;
|
|
||||||
slot = ppage->ppg_count - 1;
|
|
||||||
line = dbb->dbb_max_records - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
pp_sequence++;
|
|
||||||
slot = 0;
|
|
||||||
line = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window->win_flags & WIN_large_scan) {
|
if (window->win_flags & WIN_large_scan) {
|
||||||
CCH_RELEASE_TAIL(tdbb, window);
|
CCH_RELEASE_TAIL(tdbb, window);
|
||||||
|
@ -56,11 +56,7 @@ void DPM_fetch_fragment(Jrd::thread_db*, Jrd::record_param*, USHORT);
|
|||||||
SINT64 DPM_gen_id(Jrd::thread_db*, SLONG, bool, SINT64);
|
SINT64 DPM_gen_id(Jrd::thread_db*, SLONG, bool, SINT64);
|
||||||
bool DPM_get(Jrd::thread_db*, Jrd::record_param*, SSHORT);
|
bool DPM_get(Jrd::thread_db*, Jrd::record_param*, SSHORT);
|
||||||
ULONG DPM_get_blob(Jrd::thread_db*, Jrd::blb*, RecordNumber, bool, SLONG);
|
ULONG DPM_get_blob(Jrd::thread_db*, Jrd::blb*, RecordNumber, bool, SLONG);
|
||||||
bool DPM_next(Jrd::thread_db*, Jrd::record_param*, USHORT,
|
bool DPM_next(Jrd::thread_db*, Jrd::record_param*, USHORT, bool);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
bool,
|
|
||||||
#endif
|
|
||||||
bool);
|
|
||||||
void DPM_pages(Jrd::thread_db*, SSHORT, int, ULONG, SLONG);
|
void DPM_pages(Jrd::thread_db*, SSHORT, int, ULONG, SLONG);
|
||||||
SLONG DPM_prefetch_bitmap(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::PageBitmap*, SLONG);
|
SLONG DPM_prefetch_bitmap(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::PageBitmap*, SLONG);
|
||||||
void DPM_scan_pages(Jrd::thread_db*);
|
void DPM_scan_pages(Jrd::thread_db*);
|
||||||
|
@ -170,14 +170,6 @@ const SINT64 ISC_TICKS_PER_DAY = SECONDS_PER_DAY * ISC_TIME_SECONDS_PRECISION;
|
|||||||
const SCHAR DIALECT_3_TIMESTAMP_SCALE = -9;
|
const SCHAR DIALECT_3_TIMESTAMP_SCALE = -9;
|
||||||
const SCHAR DIALECT_1_TIMESTAMP_SCALE = 0;
|
const SCHAR DIALECT_1_TIMESTAMP_SCALE = 0;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
static const rse_get_mode g_RSE_get_mode = RSE_get_next;
|
|
||||||
#else
|
|
||||||
static const rse_get_mode g_RSE_get_mode = RSE_get_forward;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dsc* EVL_assign_to(thread_db* tdbb, jrd_nod* node)
|
dsc* EVL_assign_to(thread_db* tdbb, jrd_nod* node)
|
||||||
{
|
{
|
||||||
@ -640,7 +632,7 @@ bool EVL_boolean(thread_db* tdbb, jrd_nod* node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
RSE_open(tdbb, select);
|
RSE_open(tdbb, select);
|
||||||
value = RSE_get_record(tdbb, select, g_RSE_get_mode);
|
value = RSE_get_record(tdbb, select);
|
||||||
RSE_close(tdbb, select);
|
RSE_close(tdbb, select);
|
||||||
if (node->nod_type == nod_any)
|
if (node->nod_type == nod_any)
|
||||||
request->req_flags &= ~req_null;
|
request->req_flags &= ~req_null;
|
||||||
@ -750,10 +742,10 @@ bool EVL_boolean(thread_db* tdbb, jrd_nod* node)
|
|||||||
|
|
||||||
RecordSource* urs = reinterpret_cast<RecordSource*>(node->nod_arg[e_any_rsb]);
|
RecordSource* urs = reinterpret_cast<RecordSource*>(node->nod_arg[e_any_rsb]);
|
||||||
RSE_open(tdbb, urs);
|
RSE_open(tdbb, urs);
|
||||||
value = RSE_get_record(tdbb, urs, g_RSE_get_mode);
|
value = RSE_get_record(tdbb, urs);
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
value = !RSE_get_record(tdbb, urs, g_RSE_get_mode);
|
value = !RSE_get_record(tdbb, urs);
|
||||||
}
|
}
|
||||||
RSE_close(tdbb, urs);
|
RSE_close(tdbb, urs);
|
||||||
request->req_flags &= ~req_null;
|
request->req_flags &= ~req_null;
|
||||||
@ -1534,7 +1526,7 @@ USHORT EVL_group(thread_db* tdbb, RecordSource* rsb, jrd_nod* const node, USHORT
|
|||||||
if ((state == 0) || (state == 3))
|
if ((state == 0) || (state == 3))
|
||||||
{
|
{
|
||||||
RSE_open(tdbb, rsb);
|
RSE_open(tdbb, rsb);
|
||||||
if (!RSE_get_record(tdbb, rsb, g_RSE_get_mode))
|
if (!RSE_get_record(tdbb, rsb))
|
||||||
{
|
{
|
||||||
if (group) {
|
if (group) {
|
||||||
fini_agg_distinct(tdbb, node);
|
fini_agg_distinct(tdbb, node);
|
||||||
@ -1767,7 +1759,7 @@ USHORT EVL_group(thread_db* tdbb, RecordSource* rsb, jrd_nod* const node, USHORT
|
|||||||
if (state == 2)
|
if (state == 2)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!RSE_get_record(tdbb, rsb, g_RSE_get_mode))
|
if (!RSE_get_record(tdbb, rsb))
|
||||||
{
|
{
|
||||||
state = 2;
|
state = 2;
|
||||||
}
|
}
|
||||||
@ -2970,11 +2962,7 @@ static void compute_agg_distinct(thread_db* tdbb, jrd_nod* node)
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
UCHAR* data;
|
UCHAR* data;
|
||||||
SORT_get(tdbb, asb_impure->iasb_sort_handle, reinterpret_cast<ULONG**>(&data)
|
SORT_get(tdbb, asb_impure->iasb_sort_handle, reinterpret_cast<ULONG**>(&data));
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, RSE_get_forward
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
/* we are done, close the sort */
|
/* we are done, close the sort */
|
||||||
@ -3341,7 +3329,7 @@ static dsc* eval_statistical(thread_db* tdbb, jrd_nod* node, impure_value* impur
|
|||||||
{
|
{
|
||||||
case nod_count:
|
case nod_count:
|
||||||
flag = 0;
|
flag = 0;
|
||||||
while (RSE_get_record(tdbb, rsb, g_RSE_get_mode))
|
while (RSE_get_record(tdbb, rsb))
|
||||||
{
|
{
|
||||||
++impure->vlu_misc.vlu_long;
|
++impure->vlu_misc.vlu_long;
|
||||||
}
|
}
|
||||||
@ -3350,7 +3338,7 @@ static dsc* eval_statistical(thread_db* tdbb, jrd_nod* node, impure_value* impur
|
|||||||
/*
|
/*
|
||||||
case nod_count2:
|
case nod_count2:
|
||||||
flag = 0;
|
flag = 0;
|
||||||
while (RSE_get_record(tdbb, rsb, g_RSE_get_mode))
|
while (RSE_get_record(tdbb, rsb))
|
||||||
{
|
{
|
||||||
EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
||||||
if (!(request->req_flags & req_null)) {
|
if (!(request->req_flags & req_null)) {
|
||||||
@ -3362,7 +3350,7 @@ static dsc* eval_statistical(thread_db* tdbb, jrd_nod* node, impure_value* impur
|
|||||||
|
|
||||||
case nod_min:
|
case nod_min:
|
||||||
case nod_max:
|
case nod_max:
|
||||||
while (RSE_get_record(tdbb, rsb, g_RSE_get_mode))
|
while (RSE_get_record(tdbb, rsb))
|
||||||
{
|
{
|
||||||
dsc* value = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
dsc* value = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
||||||
if (request->req_flags & req_null) {
|
if (request->req_flags & req_null) {
|
||||||
@ -3379,7 +3367,7 @@ static dsc* eval_statistical(thread_db* tdbb, jrd_nod* node, impure_value* impur
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case nod_from:
|
case nod_from:
|
||||||
if (RSE_get_record(tdbb, rsb, g_RSE_get_mode))
|
if (RSE_get_record(tdbb, rsb))
|
||||||
{
|
{
|
||||||
desc = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
desc = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
||||||
}
|
}
|
||||||
@ -3395,7 +3383,7 @@ static dsc* eval_statistical(thread_db* tdbb, jrd_nod* node, impure_value* impur
|
|||||||
|
|
||||||
case nod_average: /* total or average with dialect-1 semantics */
|
case nod_average: /* total or average with dialect-1 semantics */
|
||||||
case nod_total:
|
case nod_total:
|
||||||
while (RSE_get_record(tdbb, rsb, g_RSE_get_mode))
|
while (RSE_get_record(tdbb, rsb))
|
||||||
{
|
{
|
||||||
desc = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
desc = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
||||||
if (request->req_flags & req_null) {
|
if (request->req_flags & req_null) {
|
||||||
@ -3424,7 +3412,7 @@ static dsc* eval_statistical(thread_db* tdbb, jrd_nod* node, impure_value* impur
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case nod_average2: /* average with dialect-3 semantics */
|
case nod_average2: /* average with dialect-3 semantics */
|
||||||
while (RSE_get_record(tdbb, rsb, g_RSE_get_mode))
|
while (RSE_get_record(tdbb, rsb))
|
||||||
{
|
{
|
||||||
desc = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
desc = EVL_expr(tdbb, node->nod_arg[e_stat_value]);
|
||||||
if (request->req_flags & req_null)
|
if (request->req_flags & req_null)
|
||||||
|
330
src/jrd/exe.cpp
330
src/jrd/exe.cpp
@ -208,10 +208,6 @@ static jrd_nod* modify(thread_db*, jrd_nod*, SSHORT);
|
|||||||
static jrd_nod* receive_msg(thread_db*, jrd_nod*);
|
static jrd_nod* receive_msg(thread_db*, jrd_nod*);
|
||||||
static void release_blobs(thread_db*, jrd_req*);
|
static void release_blobs(thread_db*, jrd_req*);
|
||||||
static void release_proc_save_points(jrd_req*);
|
static void release_proc_save_points(jrd_req*);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
static jrd_nod* seek_rse(thread_db*, jrd_req*, jrd_nod*);
|
|
||||||
static void seek_rsb(thread_db*, jrd_req*, RecordSource*, USHORT, SLONG);
|
|
||||||
#endif
|
|
||||||
static jrd_nod* selct(thread_db*, jrd_nod*);
|
static jrd_nod* selct(thread_db*, jrd_nod*);
|
||||||
static void set_error(thread_db*, const xcp_repeat*, jrd_nod*);
|
static void set_error(thread_db*, const xcp_repeat*, jrd_nod*);
|
||||||
static jrd_nod* stall(thread_db*, jrd_nod*);
|
static jrd_nod* stall(thread_db*, jrd_nod*);
|
||||||
@ -238,12 +234,6 @@ const int POST_TRIG = 2;
|
|||||||
|
|
||||||
const size_t MAX_STACK_TRACE = 2048;
|
const size_t MAX_STACK_TRACE = 2048;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
static const rse_get_mode g_RSE_get_mode = RSE_get_next;
|
|
||||||
#else
|
|
||||||
static const rse_get_mode g_RSE_get_mode = RSE_get_forward;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void EXE_assignment(thread_db* tdbb, jrd_nod* node)
|
void EXE_assignment(thread_db* tdbb, jrd_nod* node)
|
||||||
{
|
{
|
||||||
@ -762,11 +752,7 @@ void EXE_receive(thread_db* tdbb,
|
|||||||
execute_looper(tdbb, request, transaction, jrd_req::req_sync);
|
execute_looper(tdbb, request, transaction, jrd_req::req_sync);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (request->req_message->nod_type == nod_stall
|
if (request->req_message->nod_type == nod_stall)
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
|| request->req_flags & req_fetch_required
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
execute_looper(tdbb, request, transaction, jrd_req::req_sync);
|
execute_looper(tdbb, request, transaction, jrd_req::req_sync);
|
||||||
}
|
}
|
||||||
@ -840,42 +826,6 @@ void EXE_receive(thread_db* tdbb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
void EXE_seek(thread_db* tdbb, jrd_req* request, USHORT direction, ULONG offset)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* E X E _ s e e k
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Seek a given request in a particular direction
|
|
||||||
* for offset records.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
SET_TDBB(tdbb);
|
|
||||||
DEV_BLKCHK(request, type_req);
|
|
||||||
|
|
||||||
/* loop through all RSEs in the request,
|
|
||||||
and describe the rsb tree for that rsb;
|
|
||||||
go backwards because items were popped
|
|
||||||
off the stack backwards */
|
|
||||||
|
|
||||||
/* find the top-level rsb in the request and seek it */
|
|
||||||
|
|
||||||
for (SLONG i = request->req_fors.getCount() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
RecordSource* rsb = request->req_fors[i];
|
|
||||||
if (rsb) {
|
|
||||||
seek_rsb(tdbb, request, rsb, direction, offset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void EXE_send(thread_db* tdbb,
|
void EXE_send(thread_db* tdbb,
|
||||||
jrd_req* request,
|
jrd_req* request,
|
||||||
USHORT msg,
|
USHORT msg,
|
||||||
@ -904,40 +854,9 @@ void EXE_send(thread_db* tdbb,
|
|||||||
|
|
||||||
jrd_nod* message;
|
jrd_nod* message;
|
||||||
jrd_nod* node;
|
jrd_nod* node;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
if (request->req_operation != jrd_req::req_receive)
|
||||||
/* look for an asynchronous send message--if such
|
ERR_post(Arg::Gds(isc_req_sync));
|
||||||
a message was defined, we allow the user to send
|
node = request->req_message;
|
||||||
us a message at any time during request execution */
|
|
||||||
jrd_nod* save_next = NULL;
|
|
||||||
jrd_nod* save_message = NULL;
|
|
||||||
jrd_req::req_s save_operation = jrd_req::req_evaluate;
|
|
||||||
|
|
||||||
if ((message = request->req_async_message) && (node = message->nod_arg[e_send_message]) &&
|
|
||||||
(msg == (USHORT)(ULONG) node->nod_arg[e_msg_number]))
|
|
||||||
{
|
|
||||||
/* save the current state of the request so we can go
|
|
||||||
back to what was interrupted */
|
|
||||||
|
|
||||||
save_operation = request->req_operation;
|
|
||||||
save_message = request->req_message;
|
|
||||||
save_next = request->req_next;
|
|
||||||
|
|
||||||
request->req_operation = jrd_req::req_receive;
|
|
||||||
request->req_message = node;
|
|
||||||
request->req_next = message->nod_arg[e_send_statement];
|
|
||||||
|
|
||||||
/* indicate that we are processing an asynchronous message */
|
|
||||||
|
|
||||||
request->req_flags |= req_async_processing;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#endif
|
|
||||||
if (request->req_operation != jrd_req::req_receive)
|
|
||||||
ERR_post(Arg::Gds(isc_req_sync));
|
|
||||||
node = request->req_message;
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
jrd_tra* transaction = request->req_transaction;
|
jrd_tra* transaction = request->req_transaction;
|
||||||
const bool external = request->req_procedure && request->req_procedure->prc_external;
|
const bool external = request->req_procedure && request->req_procedure->prc_external;
|
||||||
@ -1029,18 +948,6 @@ void EXE_send(thread_db* tdbb,
|
|||||||
|
|
||||||
if (!external)
|
if (!external)
|
||||||
execute_looper(tdbb, request, transaction, jrd_req::req_proceed);
|
execute_looper(tdbb, request, transaction, jrd_req::req_proceed);
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (save_next) {
|
|
||||||
/* if the message was sent asynchronously, restore all the
|
|
||||||
previous values so that whatever we were trying to do when
|
|
||||||
the message came in is what we do next */
|
|
||||||
|
|
||||||
request->req_operation = save_operation;
|
|
||||||
request->req_message = save_message;
|
|
||||||
request->req_next = save_next;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2205,7 +2112,7 @@ jrd_nod* EXE_looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case jrd_req::req_sync:
|
case jrd_req::req_sync:
|
||||||
if (RSE_get_record(tdbb, (RecordSource*) node->nod_arg[e_for_rsb], g_RSE_get_mode))
|
if (RSE_get_record(tdbb, (RecordSource*) node->nod_arg[e_for_rsb]))
|
||||||
{
|
{
|
||||||
node = node->nod_arg[e_for_statement];
|
node = node->nod_arg[e_for_statement];
|
||||||
request->req_operation = jrd_req::req_evaluate;
|
request->req_operation = jrd_req::req_evaluate;
|
||||||
@ -2281,6 +2188,7 @@ jrd_nod* EXE_looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node)
|
|||||||
node = node->nod_parent;
|
node = node->nod_parent;
|
||||||
break;
|
break;
|
||||||
case blr_cursor_fetch:
|
case blr_cursor_fetch:
|
||||||
|
case blr_cursor_fetch_scroll:
|
||||||
switch (request->req_operation)
|
switch (request->req_operation)
|
||||||
{
|
{
|
||||||
case jrd_req::req_evaluate:
|
case jrd_req::req_evaluate:
|
||||||
@ -2292,13 +2200,8 @@ jrd_nod* EXE_looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node)
|
|||||||
ERR_post(Arg::Gds(isc_stream_eof));
|
ERR_post(Arg::Gds(isc_stream_eof));
|
||||||
}
|
}
|
||||||
request->req_records_affected.clear();
|
request->req_records_affected.clear();
|
||||||
// perform preliminary navigation, if specified
|
|
||||||
if (node->nod_arg[e_cursor_stmt_seek]) {
|
|
||||||
node = node->nod_arg[e_cursor_stmt_seek];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// fetch one record
|
// fetch one record
|
||||||
if (RSE_get_record(tdbb, rsb, g_RSE_get_mode))
|
if (RSE_get_record(tdbb, rsb))
|
||||||
{
|
{
|
||||||
node = node->nod_arg[e_cursor_stmt_into];
|
node = node->nod_arg[e_cursor_stmt_into];
|
||||||
request->req_operation = jrd_req::req_evaluate;
|
request->req_operation = jrd_req::req_evaluate;
|
||||||
@ -2804,12 +2707,6 @@ jrd_nod* EXE_looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
case nod_seek:
|
|
||||||
node = seek_rse(tdbb, request, node);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case nod_set_generator:
|
case nod_set_generator:
|
||||||
case nod_set_generator2:
|
case nod_set_generator2:
|
||||||
if (request->req_operation == jrd_req::req_evaluate)
|
if (request->req_operation == jrd_req::req_evaluate)
|
||||||
@ -2949,11 +2846,7 @@ jrd_nod* EXE_looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node)
|
|||||||
// request unless we are in the middle of processing an
|
// request unless we are in the middle of processing an
|
||||||
// asynchronous message
|
// asynchronous message
|
||||||
|
|
||||||
if (in_node->nod_type != nod_stmt_expr && !node
|
if (in_node->nod_type != nod_stmt_expr && !node)
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
&& !(request->req_flags & req_async_processing)
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
// Close active cursors
|
// Close active cursors
|
||||||
if (request->req_cursors)
|
if (request->req_cursors)
|
||||||
@ -3408,213 +3301,6 @@ static void release_proc_save_points(jrd_req* request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
static jrd_nod* seek_rse(thread_db* tdbb, jrd_req* request, jrd_nod* node)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* s e e k _ r s e
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Execute a nod_seek, which specifies
|
|
||||||
* a direction and offset in which to
|
|
||||||
* scroll a record selection expression.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
SET_TDBB(tdbb);
|
|
||||||
DEV_BLKCHK(node, type_nod);
|
|
||||||
|
|
||||||
if (request->req_operation == jrd_req::req_proceed)
|
|
||||||
{
|
|
||||||
/* get input arguments */
|
|
||||||
|
|
||||||
const dsc* desc = EVL_expr(tdbb, node->nod_arg[e_seek_direction]);
|
|
||||||
const USHORT direction = (desc && !(request->req_flags & req_null)) ?
|
|
||||||
MOV_get_long(desc, 0) : MAX_USHORT;
|
|
||||||
|
|
||||||
desc = EVL_expr(tdbb, node->nod_arg[e_seek_offset]);
|
|
||||||
const SLONG offset = (desc && !(request->req_flags & req_null)) ? MOV_get_long(desc, 0) : 0;
|
|
||||||
|
|
||||||
RecordSelExpr* rse = (RecordSelExpr*) node->nod_arg[e_seek_rse];
|
|
||||||
|
|
||||||
seek_rsb(tdbb, request, rse->rse_rsb, direction, offset);
|
|
||||||
|
|
||||||
request->req_operation = jrd_req::req_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node->nod_parent;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
static void seek_rsb(thread_db* tdbb,
|
|
||||||
jrd_req* request, RecordSource* rsb, USHORT direction, SLONG offset)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* s e e k _ r s b
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Allow scrolling through a stream as defined
|
|
||||||
* by the input rsb. Handles multiple seeking.
|
|
||||||
* Uses RSE_get_record() to do the actual work.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
SET_TDBB(tdbb);
|
|
||||||
DEV_BLKCHK(rsb, type_rsb);
|
|
||||||
irsb* impure = (IRSB) ((UCHAR *) request + rsb->rsb_impure);
|
|
||||||
|
|
||||||
/* look past any boolean to the actual stream */
|
|
||||||
|
|
||||||
if (rsb->rsb_type == rsb_boolean)
|
|
||||||
{
|
|
||||||
seek_rsb(tdbb, request, rsb->rsb_next, direction, offset);
|
|
||||||
|
|
||||||
/* set the backwards flag */
|
|
||||||
|
|
||||||
const irsb* next_impure = (IRSB) ((UCHAR *) request + rsb->rsb_next->rsb_impure);
|
|
||||||
|
|
||||||
if (next_impure->irsb_flags & irsb_last_backwards)
|
|
||||||
impure->irsb_flags |= irsb_last_backwards;
|
|
||||||
else
|
|
||||||
impure->irsb_flags &= ~irsb_last_backwards;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do simple boundary checking for bof and eof */
|
|
||||||
|
|
||||||
switch (direction)
|
|
||||||
{
|
|
||||||
case blr_forward:
|
|
||||||
if (impure->irsb_flags & irsb_eof)
|
|
||||||
ERR_post(Arg::Gds(isc_stream_eof));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case blr_backward:
|
|
||||||
if (impure->irsb_flags & irsb_bof)
|
|
||||||
ERR_post(Arg::Gds(isc_stream_bof));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case blr_bof_forward:
|
|
||||||
case blr_eof_backward:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// was: BUGCHECK(232);
|
|
||||||
// replaced with this error to be consistent with find()
|
|
||||||
ERR_post(Arg::Gds(isc_invalid_direction));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the actual offset to seek may be one less because the next time
|
|
||||||
through the blr_for loop we will seek one record--flag the fact
|
|
||||||
that a fetch is required on this stream in case it doesn't happen
|
|
||||||
(for example when GPRE generates BLR which does not stall prior to
|
|
||||||
the blr_for, as DSQL does) */
|
|
||||||
|
|
||||||
if (offset > 0)
|
|
||||||
switch (direction)
|
|
||||||
{
|
|
||||||
case blr_forward:
|
|
||||||
case blr_bof_forward:
|
|
||||||
if (!(impure->irsb_flags & irsb_last_backwards)) {
|
|
||||||
offset--;
|
|
||||||
if (!(impure->irsb_flags & irsb_bof))
|
|
||||||
request->req_flags |= req_fetch_required;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case blr_backward:
|
|
||||||
case blr_eof_backward:
|
|
||||||
if (impure->irsb_flags & irsb_last_backwards) {
|
|
||||||
offset--;
|
|
||||||
if (!(impure->irsb_flags & irsb_eof))
|
|
||||||
request->req_flags |= req_fetch_required;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now do the actual seek */
|
|
||||||
|
|
||||||
switch (direction)
|
|
||||||
{
|
|
||||||
case blr_forward: /* go forward from the current location */
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
without constantly sending messages to the engine */
|
|
||||||
|
|
||||||
impure->irsb_flags &= ~irsb_last_backwards;
|
|
||||||
|
|
||||||
while (offset) {
|
|
||||||
offset--;
|
|
||||||
if (!RSE_get_record(tdbb, rsb, RSE_get_next))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case blr_backward: /* go backward from the current location */
|
|
||||||
|
|
||||||
impure->irsb_flags |= irsb_last_backwards;
|
|
||||||
|
|
||||||
while (offset) {
|
|
||||||
offset--;
|
|
||||||
if (!RSE_get_record(tdbb, rsb, RSE_get_next))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case blr_bof_forward: /* go forward from the beginning of the stream */
|
|
||||||
|
|
||||||
RSE_close(tdbb, rsb);
|
|
||||||
RSE_open(tdbb, rsb);
|
|
||||||
|
|
||||||
impure->irsb_flags &= ~irsb_last_backwards;
|
|
||||||
|
|
||||||
while (offset) {
|
|
||||||
offset--;
|
|
||||||
if (!RSE_get_record(tdbb, rsb, RSE_get_next))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case blr_eof_backward: /* go backward from the end of the stream */
|
|
||||||
|
|
||||||
RSE_close(tdbb, rsb);
|
|
||||||
RSE_open(tdbb, rsb);
|
|
||||||
|
|
||||||
/* if this is a stream type which uses bof and eof flags,
|
|
||||||
reverse the sense of bof and eof in this case */
|
|
||||||
|
|
||||||
if (impure->irsb_flags & irsb_bof) {
|
|
||||||
impure->irsb_flags &= ~irsb_bof;
|
|
||||||
impure->irsb_flags |= irsb_eof;
|
|
||||||
}
|
|
||||||
|
|
||||||
impure->irsb_flags |= irsb_last_backwards;
|
|
||||||
|
|
||||||
while (offset) {
|
|
||||||
offset--;
|
|
||||||
if (!RSE_get_record(tdbb, rsb, RSE_get_next))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Should never go here, because of the boundary
|
|
||||||
// check above, but anyway...
|
|
||||||
BUGCHECK(232);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static jrd_nod* selct(thread_db* tdbb, jrd_nod* node)
|
static jrd_nod* selct(thread_db* tdbb, jrd_nod* node)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
|
@ -134,9 +134,6 @@ public:
|
|||||||
USHORT rse_count;
|
USHORT rse_count;
|
||||||
USHORT rse_jointype; // inner, left, full
|
USHORT rse_jointype; // inner, left, full
|
||||||
bool rse_writelock;
|
bool rse_writelock;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
RecordSource* rse_rsb;
|
|
||||||
#endif
|
|
||||||
jrd_nod* rse_first;
|
jrd_nod* rse_first;
|
||||||
jrd_nod* rse_skip;
|
jrd_nod* rse_skip;
|
||||||
jrd_nod* rse_boolean;
|
jrd_nod* rse_boolean;
|
||||||
@ -145,17 +142,13 @@ public:
|
|||||||
jrd_nod* rse_aggregate; // singleton aggregate for optimizing to index
|
jrd_nod* rse_aggregate; // singleton aggregate for optimizing to index
|
||||||
jrd_nod* rse_plan; // user-specified access plan
|
jrd_nod* rse_plan; // user-specified access plan
|
||||||
VarInvariantArray *rse_invariants; // Invariant nodes bound to top-level RSE
|
VarInvariantArray *rse_invariants; // Invariant nodes bound to top-level RSE
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
jrd_nod* rse_async_message; // asynchronous message to send for scrolling
|
|
||||||
#endif
|
|
||||||
jrd_nod* rse_relation[1];
|
jrd_nod* rse_relation[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// First one is obsolete: was used for PC_ENGINE
|
const int rse_scrollable = 1; // flags RSE as a scrollable cursor
|
||||||
//const int rse_stream = 1; // flags RecordSelExpr-type node as a blr_stream type
|
const int rse_singular = 2; // flags RSE as a singleton select
|
||||||
const int rse_singular = 2; // flags RecordSelExpr-type node as from a singleton select
|
const int rse_variant = 4; // flags RSE as variant (not invariant?)
|
||||||
const int rse_variant = 4; // flags RecordSelExpr as variant (not invariant?)
|
|
||||||
|
|
||||||
// Number of nodes may fit into nod_arg of normal node to get to rse_relation
|
// Number of nodes may fit into nod_arg of normal node to get to rse_relation
|
||||||
const size_t rse_delta = (sizeof(RecordSelExpr) - sizeof(jrd_nod)) / sizeof(jrd_nod::blk_repeat_type);
|
const size_t rse_delta = (sizeof(RecordSelExpr) - sizeof(jrd_nod)) / sizeof(jrd_nod::blk_repeat_type);
|
||||||
@ -461,14 +454,6 @@ const int e_cast_iteminfo = 2;
|
|||||||
const int e_cast_length = 3;
|
const int e_cast_length = 3;
|
||||||
|
|
||||||
|
|
||||||
// CVC: These belong to SCROLLABLE_CURSORS, but I can't mark them with the macro
|
|
||||||
// because e_seek_length is used in blrtable.h.
|
|
||||||
const int e_seek_offset = 0; // for seeking through a stream
|
|
||||||
const int e_seek_direction = 1;
|
|
||||||
const int e_seek_rse = 2;
|
|
||||||
const int e_seek_length = 3;
|
|
||||||
|
|
||||||
|
|
||||||
// This is for the plan node
|
// This is for the plan node
|
||||||
const int e_retrieve_relation = 0;
|
const int e_retrieve_relation = 0;
|
||||||
const int e_retrieve_access_type = 1;
|
const int e_retrieve_access_type = 1;
|
||||||
@ -496,11 +481,12 @@ const int e_dcl_cursor_number = 2;
|
|||||||
const int e_dcl_cursor_rsb = 3;
|
const int e_dcl_cursor_rsb = 3;
|
||||||
const int e_dcl_cursor_length = 4;
|
const int e_dcl_cursor_length = 4;
|
||||||
|
|
||||||
const int e_cursor_stmt_op = 0;
|
const int e_cursor_stmt_op = 0;
|
||||||
const int e_cursor_stmt_number = 1;
|
const int e_cursor_stmt_number = 1;
|
||||||
const int e_cursor_stmt_seek = 2;
|
const int e_cursor_stmt_scroll_op = 2;
|
||||||
const int e_cursor_stmt_into = 3;
|
const int e_cursor_stmt_scroll_val = 3;
|
||||||
const int e_cursor_stmt_length = 4;
|
const int e_cursor_stmt_into = 4;
|
||||||
|
const int e_cursor_stmt_length = 5;
|
||||||
|
|
||||||
const int e_strlen_value = 0;
|
const int e_strlen_value = 0;
|
||||||
const int e_strlen_type = 1;
|
const int e_strlen_type = 1;
|
||||||
@ -808,10 +794,6 @@ public:
|
|||||||
: /*csb_node(0),
|
: /*csb_node(0),
|
||||||
csb_variables(0),
|
csb_variables(0),
|
||||||
csb_dependencies(0),
|
csb_dependencies(0),
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
csb_current_rse(0),
|
|
||||||
csb_async_message(0),
|
|
||||||
#endif
|
|
||||||
csb_count(0),
|
csb_count(0),
|
||||||
csb_n_stream(0),
|
csb_n_stream(0),
|
||||||
csb_msg_number(0),
|
csb_msg_number(0),
|
||||||
@ -879,12 +861,6 @@ public:
|
|||||||
Firebird::Array<jrd_nod*> csb_invariants; // stack of invariant nodes
|
Firebird::Array<jrd_nod*> csb_invariants; // stack of invariant nodes
|
||||||
Firebird::Array<jrd_node_base*> csb_current_nodes; // RecordSelExpr's and other invariant
|
Firebird::Array<jrd_node_base*> csb_current_nodes; // RecordSelExpr's and other invariant
|
||||||
// candidates within whose scope we are
|
// candidates within whose scope we are
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
RecordSelExpr* csb_current_rse; // this holds the RecordSelExpr currently being processed;
|
|
||||||
// unlike the current_rses stack, it references any
|
|
||||||
// expanded view RecordSelExpr
|
|
||||||
jrd_nod* csb_async_message; // asynchronous message to send to request
|
|
||||||
#endif
|
|
||||||
USHORT csb_n_stream; // Next available stream
|
USHORT csb_n_stream; // Next available stream
|
||||||
USHORT csb_msg_number; // Highest used message number
|
USHORT csb_msg_number; // Highest used message number
|
||||||
SLONG csb_impure; // Next offset into impure area
|
SLONG csb_impure; // Next offset into impure area
|
||||||
|
@ -44,9 +44,6 @@ void EXE_receive(Jrd::thread_db*, Jrd::jrd_req*, USHORT, USHORT, UCHAR*, bool =
|
|||||||
void EXE_send(Jrd::thread_db*, Jrd::jrd_req*, USHORT, USHORT, const UCHAR*);
|
void EXE_send(Jrd::thread_db*, Jrd::jrd_req*, USHORT, USHORT, const UCHAR*);
|
||||||
void EXE_start(Jrd::thread_db*, Jrd::jrd_req*, Jrd::jrd_tra*);
|
void EXE_start(Jrd::thread_db*, Jrd::jrd_req*, Jrd::jrd_tra*);
|
||||||
void EXE_unwind(Jrd::thread_db*, Jrd::jrd_req*);
|
void EXE_unwind(Jrd::thread_db*, Jrd::jrd_req*);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
void EXE_seek(Jrd::thread_db*, Jrd::jrd_req*, USHORT, ULONG);
|
|
||||||
#endif
|
|
||||||
void EXE_verb_cleanup(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction);
|
void EXE_verb_cleanup(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction);
|
||||||
|
|
||||||
namespace Jrd
|
namespace Jrd
|
||||||
|
@ -3449,13 +3449,11 @@ static void blr_print_verb(gds_ctl* control, SSHORT level)
|
|||||||
case op_cursor_stmt:
|
case op_cursor_stmt:
|
||||||
blr_operator = blr_print_byte(control);
|
blr_operator = blr_print_byte(control);
|
||||||
blr_print_word(control);
|
blr_print_word(control);
|
||||||
if (blr_operator == blr_cursor_fetch)
|
offset = blr_print_line(control, (SSHORT) offset);
|
||||||
|
if (blr_operator == blr_cursor_fetch_scroll)
|
||||||
{
|
{
|
||||||
#ifdef SCROLLABLE_CURSORS
|
blr_print_verb(control, level);
|
||||||
if (control->ctl_blr_reader.peekByte() == blr_seek) {
|
blr_print_verb(control, level);
|
||||||
blr_print_verb(control, level);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
offset = blr_print_line(control, (SSHORT) offset);
|
offset = blr_print_line(control, (SSHORT) offset);
|
||||||
break;
|
break;
|
||||||
|
@ -348,11 +348,7 @@ void IDX_create_index(thread_db* tdbb,
|
|||||||
|
|
||||||
// Loop thru the relation computing index keys. If there are old versions, find them, too.
|
// Loop thru the relation computing index keys. If there are old versions, find them, too.
|
||||||
temporary_key key;
|
temporary_key key;
|
||||||
while (DPM_next(tdbb, &primary, LCK_read,
|
while (DPM_next(tdbb, &primary, LCK_read, false))
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
false,
|
|
||||||
#endif
|
|
||||||
false))
|
|
||||||
{
|
{
|
||||||
if (!VIO_garbage_collect(tdbb, &primary, transaction))
|
if (!VIO_garbage_collect(tdbb, &primary, transaction))
|
||||||
continue;
|
continue;
|
||||||
|
@ -397,13 +397,8 @@ void INF_database_info(const UCHAR* items,
|
|||||||
* base_level represents what the server 'knows'
|
* base_level represents what the server 'knows'
|
||||||
*/
|
*/
|
||||||
STUFF(p, 1); /* Count */
|
STUFF(p, 1); /* Count */
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
UPDATE WITH VERSION OF SERVER SUPPORTING
|
|
||||||
SCROLLABLE CURSORS STUFF(p, 5); /* base level of scrollable cursors */
|
|
||||||
#else
|
|
||||||
/* IB_MAJOR_VER is defined as a character string */
|
/* IB_MAJOR_VER is defined as a character string */
|
||||||
STUFF(p, DBSERVER_BASE_LEVEL); /* base level of current version */
|
STUFF(p, DBSERVER_BASE_LEVEL); /* base level of current version */
|
||||||
#endif
|
|
||||||
length = p - buffer;
|
length = p - buffer;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2799,12 +2799,7 @@ ISC_STATUS GDS_RECEIVE(ISC_STATUS* user_status,
|
|||||||
USHORT msg_type,
|
USHORT msg_type,
|
||||||
USHORT msg_length,
|
USHORT msg_length,
|
||||||
SCHAR* msg,
|
SCHAR* msg,
|
||||||
SSHORT level
|
SSHORT level)
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, USHORT direction,
|
|
||||||
ULONG offset
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -2826,11 +2821,7 @@ ISC_STATUS GDS_RECEIVE(ISC_STATUS* user_status,
|
|||||||
check_database(tdbb);
|
check_database(tdbb);
|
||||||
check_transaction(tdbb, request->req_transaction);
|
check_transaction(tdbb, request->req_transaction);
|
||||||
|
|
||||||
JRD_receive(tdbb, request, msg_type, msg_length, reinterpret_cast<UCHAR*>(msg), level
|
JRD_receive(tdbb, request, msg_type, msg_length, reinterpret_cast<UCHAR*>(msg), level);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, direction, offset
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
@ -3841,11 +3832,7 @@ ISC_STATUS GDS_DSQL_EXECUTE_IMMEDIATE(ISC_STATUS* user_status,
|
|||||||
ISC_STATUS GDS_DSQL_FETCH(ISC_STATUS* user_status,
|
ISC_STATUS GDS_DSQL_FETCH(ISC_STATUS* user_status,
|
||||||
dsql_req** stmt_handle,
|
dsql_req** stmt_handle,
|
||||||
USHORT blr_length, const SCHAR* blr,
|
USHORT blr_length, const SCHAR* blr,
|
||||||
USHORT /*msg_type*/, USHORT msg_length, SCHAR* dsql_msg_buf
|
USHORT /*msg_type*/, USHORT msg_length, SCHAR* dsql_msg_buf)
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, USHORT direction, SLONG offset
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
ISC_STATUS return_code = FB_SUCCESS;
|
ISC_STATUS return_code = FB_SUCCESS;
|
||||||
|
|
||||||
@ -3859,11 +3846,7 @@ ISC_STATUS GDS_DSQL_FETCH(ISC_STATUS* user_status,
|
|||||||
check_database(tdbb);
|
check_database(tdbb);
|
||||||
|
|
||||||
return_code = DSQL_fetch(tdbb, statement, blr_length, reinterpret_cast<const UCHAR*>(blr),
|
return_code = DSQL_fetch(tdbb, statement, blr_length, reinterpret_cast<const UCHAR*>(blr),
|
||||||
/*msg_type,*/ msg_length, reinterpret_cast<UCHAR*>(dsql_msg_buf)
|
/*msg_type,*/ msg_length, reinterpret_cast<UCHAR*>(dsql_msg_buf));
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, direction, offset
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
@ -6340,11 +6323,7 @@ void JRD_ddl(thread_db* tdbb, /*Jrd::Attachment* attachment,*/ jrd_tra* transact
|
|||||||
|
|
||||||
|
|
||||||
void JRD_receive(thread_db* tdbb, jrd_req* request, USHORT msg_type, USHORT msg_length,
|
void JRD_receive(thread_db* tdbb, jrd_req* request, USHORT msg_type, USHORT msg_length,
|
||||||
UCHAR* msg, SSHORT level
|
UCHAR* msg, SSHORT level)
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, USHORT direction, ULONG offset
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -6358,11 +6337,6 @@ void JRD_receive(thread_db* tdbb, jrd_req* request, USHORT msg_type, USHORT msg_
|
|||||||
**************************************/
|
**************************************/
|
||||||
verify_request_synchronization(request, level);
|
verify_request_synchronization(request, level);
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (direction)
|
|
||||||
EXE_seek(tdbb, request, direction, offset);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
EXE_receive(tdbb, request, msg_type, msg_length, msg, true);
|
EXE_receive(tdbb, request, msg_type, msg_length, msg, true);
|
||||||
|
|
||||||
check_autocommit(request, tdbb);
|
check_autocommit(request, tdbb);
|
||||||
|
@ -104,12 +104,7 @@ ISC_STATUS jrd8_execute(ISC_STATUS*, Jrd::jrd_tra**, Jrd::dsql_req**, USHORT, co
|
|||||||
ISC_STATUS jrd8_execute_immediate(ISC_STATUS*, Jrd::Attachment**, Jrd::jrd_tra**, USHORT, const TEXT*,
|
ISC_STATUS jrd8_execute_immediate(ISC_STATUS*, Jrd::Attachment**, Jrd::jrd_tra**, USHORT, const TEXT*,
|
||||||
USHORT, USHORT, const SCHAR*, USHORT, USHORT, const SCHAR*,
|
USHORT, USHORT, const SCHAR*, USHORT, USHORT, const SCHAR*,
|
||||||
USHORT, SCHAR*, USHORT, USHORT, SCHAR*);
|
USHORT, SCHAR*, USHORT, USHORT, SCHAR*);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS jrd8_fetch(ISC_STATUS*, Jrd::dsql_req**, USHORT, const SCHAR*, USHORT, USHORT, SCHAR*,
|
|
||||||
USHORT, SLONG);
|
|
||||||
#else
|
|
||||||
ISC_STATUS jrd8_fetch(ISC_STATUS*, Jrd::dsql_req**, USHORT, const SCHAR*, USHORT, USHORT, SCHAR*);
|
ISC_STATUS jrd8_fetch(ISC_STATUS*, Jrd::dsql_req**, USHORT, const SCHAR*, USHORT, USHORT, SCHAR*);
|
||||||
#endif // SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS jrd8_free_statement(ISC_STATUS*, Jrd::dsql_req**, USHORT);
|
ISC_STATUS jrd8_free_statement(ISC_STATUS*, Jrd::dsql_req**, USHORT);
|
||||||
ISC_STATUS jrd8_insert(ISC_STATUS*, Jrd::dsql_req**, USHORT, const SCHAR*, USHORT, USHORT, const SCHAR*);
|
ISC_STATUS jrd8_insert(ISC_STATUS*, Jrd::dsql_req**, USHORT, const SCHAR*, USHORT, USHORT, const SCHAR*);
|
||||||
ISC_STATUS jrd8_prepare(ISC_STATUS*, Jrd::jrd_tra**, Jrd::dsql_req**, USHORT, const TEXT*,
|
ISC_STATUS jrd8_prepare(ISC_STATUS*, Jrd::jrd_tra**, Jrd::dsql_req**, USHORT, const TEXT*,
|
||||||
@ -143,11 +138,7 @@ void JRD_autocommit_ddl(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction);
|
|||||||
void JRD_ddl(Jrd::thread_db* tdbb, /*Jrd::Attachment* attachment,*/ Jrd::jrd_tra* transaction,
|
void JRD_ddl(Jrd::thread_db* tdbb, /*Jrd::Attachment* attachment,*/ Jrd::jrd_tra* transaction,
|
||||||
USHORT ddl_length, const UCHAR* ddl, const Firebird::string& sqlText);
|
USHORT ddl_length, const UCHAR* ddl, const Firebird::string& sqlText);
|
||||||
void JRD_receive(Jrd::thread_db* tdbb, Jrd::jrd_req* request, USHORT msg_type, USHORT msg_length,
|
void JRD_receive(Jrd::thread_db* tdbb, Jrd::jrd_req* request, USHORT msg_type, USHORT msg_length,
|
||||||
UCHAR* msg, SSHORT level
|
UCHAR* msg, SSHORT level);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, USHORT direction, ULONG offset
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
void JRD_request_info(Jrd::thread_db* tdbb, Jrd::jrd_req* request, SSHORT level, SSHORT item_length,
|
void JRD_request_info(Jrd::thread_db* tdbb, Jrd::jrd_req* request, SSHORT level, SSHORT item_length,
|
||||||
const UCHAR* items, SLONG buffer_length, UCHAR* buffer);
|
const UCHAR* items, SLONG buffer_length, UCHAR* buffer);
|
||||||
void JRD_start(Jrd::thread_db* tdbb, Jrd::jrd_req* request, Jrd::jrd_tra* transaction, SSHORT level);
|
void JRD_start(Jrd::thread_db* tdbb, Jrd::jrd_req* request, Jrd::jrd_tra* transaction, SSHORT level);
|
||||||
|
493
src/jrd/nav.cpp
493
src/jrd/nav.cpp
@ -56,96 +56,19 @@ using namespace Jrd;
|
|||||||
static int compare_keys(const index_desc*, const UCHAR*, USHORT,
|
static int compare_keys(const index_desc*, const UCHAR*, USHORT,
|
||||||
const temporary_key*, USHORT);
|
const temporary_key*, USHORT);
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
static void expand_index(WIN *);
|
|
||||||
#endif
|
|
||||||
static btree_exp* find_current(exp_index_buf*, Ods::btree_page*, const UCHAR*);
|
static btree_exp* find_current(exp_index_buf*, Ods::btree_page*, const UCHAR*);
|
||||||
static bool find_saved_node(thread_db* tdbb, RecordSource*, IRSB_NAV, WIN*, UCHAR**);
|
static bool find_saved_node(thread_db* tdbb, RecordSource*, IRSB_NAV, WIN*, UCHAR**);
|
||||||
static UCHAR* get_position(thread_db*, RecordSource*, IRSB_NAV, WIN *, rse_get_mode, btree_exp**);
|
static UCHAR* get_position(thread_db*, RecordSource*, IRSB_NAV, WIN *, btree_exp**);
|
||||||
static bool get_record(thread_db* tdbb, RecordSource*, IRSB_NAV, record_param*, temporary_key*, bool);
|
static bool get_record(thread_db* tdbb, RecordSource*, IRSB_NAV, record_param*, temporary_key*, bool);
|
||||||
static void init_fetch(IRSB_NAV);
|
static void init_fetch(IRSB_NAV);
|
||||||
static UCHAR* nav_open(thread_db* tdbb, RecordSource*, IRSB_NAV, WIN *, rse_get_mode); //, btree_exp**);
|
static UCHAR* nav_open(thread_db* tdbb, RecordSource*, IRSB_NAV, WIN *);
|
||||||
static void set_page(IRSB_NAV impure, WIN* window);
|
static void set_page(IRSB_NAV impure, WIN* window);
|
||||||
static void set_position(IRSB_NAV, record_param*, WIN*, const UCHAR*, btree_exp*, const UCHAR*, USHORT);
|
static void set_position(IRSB_NAV, record_param*, WIN*, const UCHAR*, btree_exp*, const UCHAR*, USHORT);
|
||||||
static bool setup_bitmaps(thread_db* tdbb, RecordSource*, IRSB_NAV);
|
static bool setup_bitmaps(thread_db* tdbb, RecordSource*, IRSB_NAV);
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
exp_index_buf* NAV_expand_index(WIN * window, IRSB_NAV impure)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* N A V _ e x p a n d _ i n d e x
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Given a window with a btree leaf page loaded into it,
|
|
||||||
* expand the index page into a form that facilitates walking
|
|
||||||
* backward through it. Each node's data is decompressed.
|
|
||||||
* Since the prefix field is not needed, it contains an offset to
|
|
||||||
* the prior node.
|
|
||||||
*
|
|
||||||
* If an impure pointer is passed, set the current node on the
|
|
||||||
* expanded page to match that on the corresponding btree page.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
|
|
||||||
// allocate the expanded page to allow room for all nodes fully expanded,
|
|
||||||
// plus leave room for an extra node with zero-length tail
|
|
||||||
// (note that the difference in size of a btree_exp node versus a btree_nod node could
|
|
||||||
// be deducted, but there is no easy way to get the no. of nodes on page) */
|
|
||||||
|
|
||||||
// if the right version of expanded page is available, there
|
|
||||||
// is no work to be done
|
|
||||||
exp_index_buf* expanded_page = window->win_expanded_buffer;
|
|
||||||
if (expanded_page && (expanded_page->exp_incarnation == CCH_get_incarnation(window)))
|
|
||||||
{
|
|
||||||
return expanded_page;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If different incarnation, reallocate the page
|
|
||||||
if (expanded_page) {
|
|
||||||
ALL_free(expanded_page);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ods::btree_page* page = (Ods::btree_page*) window->win_buffer;
|
|
||||||
|
|
||||||
expanded_page = (exp_index_buf*) ALL_malloc(EXP_SIZE + page->btr_prefix_total +
|
|
||||||
(SLONG) page->btr_length + BTX_SIZE, ERR_jmp);
|
|
||||||
window->win_expanded_buffer = expanded_page;
|
|
||||||
expanded_page->exp_incarnation = -1;
|
|
||||||
|
|
||||||
expand_index(window);
|
|
||||||
|
|
||||||
if (!impure) {
|
|
||||||
return expanded_page;
|
|
||||||
}
|
|
||||||
|
|
||||||
// go through the nodes on the original page and reposition
|
|
||||||
UCHAR* pointer = BTreeNode::getPointerFirstNode(page);
|
|
||||||
const UCHAR* const endPointer = ((UCHAR*) page + page->btr_length);
|
|
||||||
btree_exp* expanded_node = (btree_exp*) expanded_page->exp_nodes;
|
|
||||||
const UCHAR* current_pointer = ((UCHAR*) page + impure->irsb_nav_offset);
|
|
||||||
|
|
||||||
impure->irsb_nav_expanded_offset = -1;
|
|
||||||
|
|
||||||
Ods::IndexNode node;
|
|
||||||
while (pointer < endPointer)
|
|
||||||
{
|
|
||||||
if (pointer == current_pointer) {
|
|
||||||
impure->irsb_nav_expanded_offset = (UCHAR*) expanded_node - (UCHAR*) expanded_page;
|
|
||||||
}
|
|
||||||
pointer = BTreeNode::nextNode(pointer, &expanded_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return expanded_page;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
bool NAV_get_record(thread_db* tdbb, RecordSource* rsb,
|
bool NAV_get_record(thread_db* tdbb, RecordSource* rsb,
|
||||||
IRSB_NAV impure, record_param* rpb, rse_get_mode direction)
|
IRSB_NAV impure, record_param* rpb)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -154,57 +77,20 @@ bool NAV_get_record(thread_db* tdbb, RecordSource* rsb,
|
|||||||
**************************************
|
**************************************
|
||||||
*
|
*
|
||||||
* Functional description
|
* Functional description
|
||||||
* Get a record from a stream, either in
|
* Get a record from a stream.
|
||||||
* the forward or backward direction, or the
|
|
||||||
* current record. This routine must set
|
|
||||||
* BOF or EOF properly.
|
|
||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
SET_TDBB(tdbb);
|
SET_TDBB(tdbb);
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
// before we do anything, check for the case where an ascending index
|
|
||||||
// was used to optimize a descending sort, or a descending index was
|
|
||||||
// used to optimize an ascending sort--in either case, we need to flip
|
|
||||||
// the nominal direction of navigation
|
|
||||||
if (rsb->rsb_flags & rsb_descending)
|
|
||||||
{
|
|
||||||
if (direction == RSE_get_forward) {
|
|
||||||
direction = RSE_get_backward;
|
|
||||||
}
|
|
||||||
else if (direction == RSE_get_backward) {
|
|
||||||
direction = RSE_get_forward;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
init_fetch(impure);
|
init_fetch(impure);
|
||||||
index_desc* idx = (index_desc*) ((SCHAR*) impure + (IPTR) rsb->rsb_arg[RSB_NAV_idx_offset]);
|
index_desc* idx = (index_desc*) ((SCHAR*) impure + (IPTR) rsb->rsb_arg[RSB_NAV_idx_offset]);
|
||||||
|
|
||||||
// The bitmap is only valid when we are continuing on in one
|
|
||||||
// direction. It is of no help when we change direction,
|
|
||||||
// and so we need to reset in that case.
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (((impure->irsb_flags & irsb_backwards) && direction != RSE_get_backward) ||
|
|
||||||
(!(impure->irsb_flags & irsb_backwards) && direction != RSE_get_forward))
|
|
||||||
{
|
|
||||||
RecordBitmap::reset(impure->irsb_nav_records_visited);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (direction == RSE_get_forward) {
|
|
||||||
impure->irsb_flags &= ~irsb_backwards;
|
|
||||||
}
|
|
||||||
else if (direction == RSE_get_backward) {
|
|
||||||
impure->irsb_flags |= irsb_backwards;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// find the last fetched position from the index
|
// find the last fetched position from the index
|
||||||
const USHORT pageSpaceID = rpb->rpb_relation->getPages(tdbb)->rel_pg_space_id;
|
const USHORT pageSpaceID = rpb->rpb_relation->getPages(tdbb)->rel_pg_space_id;
|
||||||
WIN window(pageSpaceID, impure->irsb_nav_page);
|
WIN window(pageSpaceID, impure->irsb_nav_page);
|
||||||
|
|
||||||
btree_exp* expanded_next = NULL;
|
btree_exp* expanded_next = NULL;
|
||||||
UCHAR* nextPointer = get_position(tdbb, rsb, impure, &window, direction, &expanded_next);
|
UCHAR* nextPointer = get_position(tdbb, rsb, impure, &window, &expanded_next);
|
||||||
if (!nextPointer)
|
if (!nextPointer)
|
||||||
return false;
|
return false;
|
||||||
temporary_key key;
|
temporary_key key;
|
||||||
@ -214,31 +100,13 @@ bool NAV_get_record(thread_db* tdbb, RecordSource* rsb,
|
|||||||
|
|
||||||
// set the upper (or lower) limit for navigational retrieval
|
// set the upper (or lower) limit for navigational retrieval
|
||||||
temporary_key upper;
|
temporary_key upper;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
if (retrieval->irb_upper_count)
|
||||||
temporary_key lower;
|
|
||||||
#endif
|
|
||||||
if ((direction == RSE_get_forward) && retrieval->irb_upper_count)
|
|
||||||
{
|
{
|
||||||
upper.key_length = impure->irsb_nav_upper_length;
|
upper.key_length = impure->irsb_nav_upper_length;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
memcpy(upper.key_data,
|
|
||||||
(impure->irsb_nav_data + (2 * (SLONG) rsb->rsb_arg[RSB_NAV_key_length])),
|
|
||||||
upper.key_length);
|
|
||||||
#else
|
|
||||||
memcpy(upper.key_data,
|
memcpy(upper.key_data,
|
||||||
(impure->irsb_nav_data + (IPTR) rsb->rsb_arg[RSB_NAV_key_length]),
|
(impure->irsb_nav_data + (IPTR) rsb->rsb_arg[RSB_NAV_key_length]),
|
||||||
upper.key_length);
|
upper.key_length);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
else if ((direction == RSE_get_backward) && retrieval->irb_lower_count)
|
|
||||||
{
|
|
||||||
lower.key_length = impure->irsb_nav_lower_length;
|
|
||||||
memcpy(lower.key_data,
|
|
||||||
(impure->irsb_nav_data + (IPTR) rsb->rsb_arg[RSB_NAV_key_length]),
|
|
||||||
lower.key_length);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// In the case of a DISTINCT, we must detect whether the key changed since the last
|
// In the case of a DISTINCT, we must detect whether the key changed since the last
|
||||||
// time a record was returned from the rsb. It is not good enough to know whether the
|
// time a record was returned from the rsb. It is not good enough to know whether the
|
||||||
@ -278,56 +146,22 @@ bool NAV_get_record(thread_db* tdbb, RecordSource* rsb,
|
|||||||
number = node.recordNumber;
|
number = node.recordNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
if (node.isEndLevel)
|
||||||
// in the backwards case, check to make sure we haven't hit the
|
break;
|
||||||
// beginning of a page, and if so fetch the left sibling page.
|
|
||||||
if (direction == RSE_get_backward)
|
if (node.isEndBucket)
|
||||||
{
|
{
|
||||||
if (pointer < BTreeNode::getPointerFirstNode(page))
|
page = (Ods::btree_page*) window.win_buffer;
|
||||||
{
|
page = (Ods::btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling,
|
||||||
exp_index_buf* expanded_page = window.win_expanded_buffer;
|
LCK_read, pag_index);
|
||||||
|
nextPointer = BTreeNode::getPointerFirstNode(page);
|
||||||
if (!page->btr_left_sibling)
|
exp_index_buf* expanded_page = window.win_expanded_buffer;
|
||||||
{
|
if (expanded_page) {
|
||||||
impure->irsb_flags |= irsb_bof;
|
expanded_next = (btree_exp*) expanded_page->exp_nodes;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
page = BTR_left_handoff(tdbb, &window, page, LCK_read);
|
|
||||||
expanded_page = NAV_expand_index(&window, 0);
|
|
||||||
nextPointer = BTR_last_node(page, expanded_page, &expanded_next);
|
|
||||||
|
|
||||||
page_changed = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// In the forwards case, check for end of page. If we find
|
|
||||||
// it, do a simple handoff to the right sibling page.
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (node.isEndLevel)
|
|
||||||
{
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
impure->irsb_flags |= irsb_eof;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (node.isEndBucket)
|
|
||||||
{
|
|
||||||
page = (Ods::btree_page*) window.win_buffer;
|
|
||||||
page = (Ods::btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling,
|
|
||||||
LCK_read, pag_index);
|
|
||||||
nextPointer = BTreeNode::getPointerFirstNode(page);
|
|
||||||
exp_index_buf* expanded_page = window.win_expanded_buffer;
|
|
||||||
if (expanded_page) {
|
|
||||||
expanded_next = (btree_exp*) expanded_page->exp_nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
page_changed = true;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page_changed = true;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the project (DISTINCT) case, we need to determine if the key has changed
|
// In the project (DISTINCT) case, we need to determine if the key has changed
|
||||||
@ -368,22 +202,13 @@ bool NAV_get_record(thread_db* tdbb, RecordSource* rsb,
|
|||||||
key.key_length = node.length + node.prefix;
|
key.key_length = node.length + node.prefix;
|
||||||
|
|
||||||
// Make sure we haven't hit the upper (or lower) limit.
|
// Make sure we haven't hit the upper (or lower) limit.
|
||||||
if ((direction == RSE_get_forward) && retrieval->irb_upper_count &&
|
if (retrieval->irb_upper_count &&
|
||||||
compare_keys(idx, key.key_data, key.key_length, &upper,
|
compare_keys(idx, key.key_data, key.key_length, &upper,
|
||||||
retrieval->irb_generic & (irb_descending | irb_partial | irb_starting)) > 0)
|
retrieval->irb_generic & (irb_descending | irb_partial | irb_starting)) > 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if ((direction == RSE_get_backward) && retrieval->irb_lower_count &&
|
|
||||||
compare_keys(idx, key.key_data, key.key_length, &lower,
|
|
||||||
retrieval->irb_generic & (irb_descending | irb_partial | irb_starting)) < 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// skip this record if:
|
// skip this record if:
|
||||||
// 1) there is an inversion tree for this index and this record
|
// 1) there is an inversion tree for this index and this record
|
||||||
// is not in the bitmap for the inversion, or
|
// is not in the bitmap for the inversion, or
|
||||||
@ -396,20 +221,9 @@ bool NAV_get_record(thread_db* tdbb, RecordSource* rsb,
|
|||||||
RecordBitmap::test(impure->irsb_nav_records_visited, number.getValue()) ||
|
RecordBitmap::test(impure->irsb_nav_records_visited, number.getValue()) ||
|
||||||
((rsb->rsb_flags & rsb_project) && !(impure->irsb_flags & irsb_key_changed)))
|
((rsb->rsb_flags & rsb_project) && !(impure->irsb_flags & irsb_key_changed)))
|
||||||
{
|
{
|
||||||
#ifdef SCROLLABLE_CURSORS
|
nextPointer = BTreeNode::nextNode(&node, pointer, flags, &expanded_node);
|
||||||
if (direction == RSE_get_backward)
|
expanded_next = expanded_node;
|
||||||
{
|
continue;
|
||||||
nextPointer = BTreeNode::previousNode(/*&node,*/ pointer, /*flags,*/ &expanded_node);
|
|
||||||
expanded_next = expanded_node;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (direction == RSE_get_forward)
|
|
||||||
{
|
|
||||||
nextPointer = BTreeNode::nextNode(&node, pointer, flags, &expanded_node);
|
|
||||||
expanded_next = expanded_node;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the current navigational position in the index
|
// reset the current navigational position in the index
|
||||||
@ -422,7 +236,7 @@ bool NAV_get_record(thread_db* tdbb, RecordSource* rsb,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPointer = get_position(tdbb, rsb, impure, &window, direction, &expanded_next);
|
nextPointer = get_position(tdbb, rsb, impure, &window, &expanded_next);
|
||||||
if (!nextPointer)
|
if (!nextPointer)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -554,72 +368,6 @@ static int compare_keys(const index_desc* idx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
static void expand_index(WIN * window)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* e x p a n d _ i n d e x
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Given a window with a btree leaf page loaded into it,
|
|
||||||
* expand the index page into a form that facilitates walking
|
|
||||||
* backward through it. Each node's data is decompressed.
|
|
||||||
* Since the prefix field is not needed, it contains an offset to
|
|
||||||
* the prior node.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
Ods::btree_page* page = (Ods::btree_page*) window->win_buffer;
|
|
||||||
exp_index_buf* expanded_page = window->win_expanded_buffer;
|
|
||||||
expanded_page->exp_incarnation = CCH_get_incarnation(window);
|
|
||||||
|
|
||||||
// go through the nodes on the original page and expand them
|
|
||||||
temporary_key key;
|
|
||||||
btree_exp* expanded_node = (btree_exp*) expanded_page->exp_nodes;
|
|
||||||
bool priorPointer = false;
|
|
||||||
UCHAR* pointer = BTreeNode::getPointerFirstNode(page);
|
|
||||||
const UCHAR* const endPointer = ((UCHAR*) page + page->btr_length);
|
|
||||||
|
|
||||||
const UCHAR flags = page->btr_header.pag_flags;
|
|
||||||
Ods::IndexNode node, priorNode;
|
|
||||||
|
|
||||||
while (pointer < endPointer)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!priorPointer) {
|
|
||||||
pointer = BTreeNode::readNode(&node, pointer, flags, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(key.key_data + node.prefix, node.data, node.length);
|
|
||||||
memcpy(expanded_node->btx_data, key.key_data, node.length + node.prefix);
|
|
||||||
|
|
||||||
// point back to the prior nodes on the expanded page and the btree page
|
|
||||||
expanded_node->btx_btr_previous_length =
|
|
||||||
priorPointer ? BTreeNode::getLeafNodeSize(&priorNode, flags) : 0;
|
|
||||||
expanded_node->btx_previous_length =
|
|
||||||
priorPointer ? priorNode.length + priorNode.prefix : 0;
|
|
||||||
|
|
||||||
priorPointer = true;
|
|
||||||
priorNode = node;
|
|
||||||
pointer = BTreeNode::nextNode(&node, pointer, flags, &expanded_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert one additional expanded node to keep track of the length of the
|
|
||||||
// last node on page--this is necessary because the end of bucket marker
|
|
||||||
// contains the length and key of the first node on the next page
|
|
||||||
expanded_node->btx_btr_previous_length =
|
|
||||||
priorPointer ? BTreeNode::getLeafNodeSize(&priorNode, flags) : 0;
|
|
||||||
expanded_node->btx_previous_length =
|
|
||||||
priorPointer ? priorNode.length + priorNode.prefix : 0;
|
|
||||||
|
|
||||||
expanded_page->exp_length =
|
|
||||||
(UCHAR*) expanded_node - (UCHAR*) expanded_page + BTX_SIZE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static btree_exp* find_current(exp_index_buf* expanded_page, Ods::btree_page* page,
|
static btree_exp* find_current(exp_index_buf* expanded_page, Ods::btree_page* page,
|
||||||
const UCHAR* current_pointer)
|
const UCHAR* current_pointer)
|
||||||
{
|
{
|
||||||
@ -742,7 +490,7 @@ static UCHAR* get_position(thread_db* tdbb,
|
|||||||
RecordSource* rsb,
|
RecordSource* rsb,
|
||||||
IRSB_NAV impure,
|
IRSB_NAV impure,
|
||||||
WIN* window,
|
WIN* window,
|
||||||
rse_get_mode direction, btree_exp** expanded_node)
|
btree_exp** expanded_node)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -759,14 +507,10 @@ static UCHAR* get_position(thread_db* tdbb,
|
|||||||
**************************************/
|
**************************************/
|
||||||
SET_TDBB(tdbb);
|
SET_TDBB(tdbb);
|
||||||
|
|
||||||
// If this is the first time, start at the beginning (or the end)
|
// If this is the first time, start at the beginning
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (!window->win_page.getPageNum() || impure->irsb_flags & (irsb_bof | irsb_eof))
|
|
||||||
#else
|
|
||||||
if (!window->win_page.getPageNum())
|
if (!window->win_page.getPageNum())
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
return nav_open(tdbb, rsb, impure, window, direction); //, expanded_node);
|
return nav_open(tdbb, rsb, impure, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
exp_index_buf* expanded_page = NULL;
|
exp_index_buf* expanded_page = NULL;
|
||||||
@ -774,15 +518,6 @@ static UCHAR* get_position(thread_db* tdbb,
|
|||||||
// Re-fetch page and get incarnation counter
|
// Re-fetch page and get incarnation counter
|
||||||
Ods::btree_page* page = (Ods::btree_page*) CCH_FETCH(tdbb, window, LCK_read, pag_index);
|
Ods::btree_page* page = (Ods::btree_page*) CCH_FETCH(tdbb, window, LCK_read, pag_index);
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
// we must ensure that if we are going backwards, we always
|
|
||||||
// have an expanded buffer (and a valid position on that page)
|
|
||||||
if (direction == RSE_get_backward) {
|
|
||||||
NAV_expand_index(window, impure);
|
|
||||||
}
|
|
||||||
expanded_page = window->win_expanded_buffer;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UCHAR* pointer = 0;
|
UCHAR* pointer = 0;
|
||||||
const UCHAR flags = page->btr_header.pag_flags;
|
const UCHAR flags = page->btr_header.pag_flags;
|
||||||
const SLONG incarnation = CCH_get_incarnation(window);
|
const SLONG incarnation = CCH_get_incarnation(window);
|
||||||
@ -807,28 +542,15 @@ static UCHAR* get_position(thread_db* tdbb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The new way of doing things is to have the current
|
// The new way of doing things is to have the current
|
||||||
// nav_offset be the last node fetched. Go forward or
|
// nav_offset be the last node fetched.
|
||||||
// backward from that point accordingly.
|
return BTreeNode::nextNode(&node, pointer, flags, expanded_node);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (direction == RSE_get_backward)
|
|
||||||
{
|
|
||||||
pointer = BTreeNode::previousNode(/*&node,*/ pointer, /*flags,*/ expanded_node);
|
|
||||||
//node = (btree_nod*) BTR_previous_node( (UCHAR*)node, expanded_node);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (direction == RSE_get_forward)
|
|
||||||
pointer = BTreeNode::nextNode(&node, pointer, flags, expanded_node);
|
|
||||||
}
|
|
||||||
return pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Page is presumably changed. If there is a previous
|
// Page is presumably changed. If there is a previous
|
||||||
// stored position in the page, go back to it if possible.
|
// stored position in the page, go back to it if possible.
|
||||||
CCH_RELEASE(tdbb, window);
|
CCH_RELEASE(tdbb, window);
|
||||||
if (!impure->irsb_nav_page) {
|
if (!impure->irsb_nav_page) {
|
||||||
return nav_open(tdbb, rsb, impure, window, direction); //, expanded_node);
|
return nav_open(tdbb, rsb, impure, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool found = find_saved_node(tdbb, rsb, impure, window, &pointer);
|
const bool found = find_saved_node(tdbb, rsb, impure, window, &pointer);
|
||||||
@ -836,41 +558,16 @@ static UCHAR* get_position(thread_db* tdbb,
|
|||||||
if (pointer)
|
if (pointer)
|
||||||
{
|
{
|
||||||
*expanded_node = find_current(window->win_expanded_buffer, page, pointer);
|
*expanded_node = find_current(window->win_expanded_buffer, page, pointer);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
if (found)
|
||||||
if (direction == RSE_get_backward)
|
|
||||||
{
|
{
|
||||||
pointer = BTreeNode::previousNode(/*&node,*/ pointer, /*flags,*/ expanded_node);
|
// in the forward case, seek to the next node only if we found
|
||||||
//node = (btree_nod*) BTR_previous_node((UCHAR*) node, expanded_node);
|
// the actual node on page; if we did not find it, we are already
|
||||||
}
|
// at the next node (such as when the node is garbage collected)
|
||||||
else
|
pointer = BTreeNode::nextNode(&node, pointer, flags, expanded_node);
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (direction == RSE_get_forward && found)
|
|
||||||
{
|
|
||||||
// in the forward case, seek to the next node only if we found
|
|
||||||
// the actual node on page; if we did not find it, we are already
|
|
||||||
// at the next node (such as when the node is garbage collected)
|
|
||||||
pointer = BTreeNode::nextNode(&node, pointer, flags, expanded_node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return pointer;
|
return pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
// As a last resort, return the first (or last if backwards)
|
|
||||||
// node on the page. The sparse bitmap will prevent us from
|
|
||||||
// seeing records we have already visited before.
|
|
||||||
if (direction == RSE_get_backward)
|
|
||||||
{
|
|
||||||
expanded_page = NAV_expand_index(window, 0);
|
|
||||||
return BTR_last_node(page, expanded_page, expanded_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expanded_page = window->win_expanded_buffer) {
|
|
||||||
*expanded_node = (btree_exp*) expanded_page->exp_nodes;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return BTreeNode::getPointerFirstNode(page);
|
return BTreeNode::getPointerFirstNode(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,14 +605,6 @@ static bool get_record(thread_db* tdbb, RecordSource* rsb, IRSB_NAV impure,
|
|||||||
tdbb->getAttachment()->att_flags |= ATT_no_cleanup; // HACK
|
tdbb->getAttachment()->att_flags |= ATT_no_cleanup; // HACK
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
// the attempt to get a record, whether successful or not, takes
|
|
||||||
// us off bof or eof (otherwise we will keep trying to retrieve
|
|
||||||
// the first record)
|
|
||||||
|
|
||||||
impure->irsb_flags &= ~(irsb_bof | irsb_eof);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
result = VIO_get(tdbb, rpb, request->req_transaction, request->req_pool);
|
result = VIO_get(tdbb, rpb, request->req_transaction, request->req_pool);
|
||||||
|
|
||||||
temporary_key value;
|
temporary_key value;
|
||||||
@ -978,7 +667,7 @@ static void init_fetch(IRSB_NAV impure)
|
|||||||
static UCHAR* nav_open(thread_db* tdbb,
|
static UCHAR* nav_open(thread_db* tdbb,
|
||||||
RecordSource* rsb,
|
RecordSource* rsb,
|
||||||
IRSB_NAV impure,
|
IRSB_NAV impure,
|
||||||
WIN* window, rse_get_mode direction) //, btree_exp** expanded_node)
|
WIN* window)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -999,100 +688,30 @@ static UCHAR* nav_open(thread_db* tdbb,
|
|||||||
set_page(impure, NULL);
|
set_page(impure, NULL);
|
||||||
impure->irsb_nav_length = 0;
|
impure->irsb_nav_length = 0;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (direction == RSE_get_forward) {
|
|
||||||
impure->irsb_flags |= irsb_bof;
|
|
||||||
}
|
|
||||||
else if (direction == RSE_get_backward) {
|
|
||||||
impure->irsb_flags |= irsb_eof;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Find the starting leaf page
|
// Find the starting leaf page
|
||||||
jrd_nod* retrieval_node = (jrd_nod*) rsb->rsb_arg[RSB_NAV_index];
|
jrd_nod* retrieval_node = (jrd_nod*) rsb->rsb_arg[RSB_NAV_index];
|
||||||
IndexRetrieval* retrieval = (IndexRetrieval*) retrieval_node->nod_arg[e_idx_retrieval];
|
IndexRetrieval* retrieval = (IndexRetrieval*) retrieval_node->nod_arg[e_idx_retrieval];
|
||||||
index_desc* idx = (index_desc*) ((SCHAR *) impure + (IPTR) rsb->rsb_arg[RSB_NAV_idx_offset]);
|
index_desc* idx = (index_desc*) ((SCHAR *) impure + (IPTR) rsb->rsb_arg[RSB_NAV_idx_offset]);
|
||||||
temporary_key lower, upper;
|
temporary_key lower, upper;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
Ods::btree_page* page = BTR_find_page(tdbb, retrieval, window, idx, &lower, &upper,
|
|
||||||
(direction == RSE_get_backward));
|
|
||||||
#else
|
|
||||||
Ods::btree_page* page = BTR_find_page(tdbb, retrieval, window, idx, &lower, &upper);
|
Ods::btree_page* page = BTR_find_page(tdbb, retrieval, window, idx, &lower, &upper);
|
||||||
#endif
|
|
||||||
set_page(impure, window);
|
set_page(impure, window);
|
||||||
|
|
||||||
|
// find the upper limit for the search
|
||||||
#ifdef SCROLLABLE_CURSORS
|
temporary_key* limit_ptr = NULL;
|
||||||
// store the upper and lower bounds for the search in the impure area for the rsb
|
|
||||||
if (retrieval->irb_lower_count)
|
|
||||||
{
|
|
||||||
impure->irsb_nav_lower_length = lower.key_length;
|
|
||||||
memcpy((impure->irsb_nav_data + (SLONG) rsb->rsb_arg[RSB_NAV_key_length]),
|
|
||||||
lower.key_data,
|
|
||||||
lower.key_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retrieval->irb_upper_count)
|
if (retrieval->irb_upper_count)
|
||||||
{
|
{
|
||||||
impure->irsb_nav_upper_length = upper.key_length;
|
impure->irsb_nav_upper_length = upper.key_length;
|
||||||
memcpy((impure->irsb_nav_data + (2 * (SLONG) rsb->rsb_arg[RSB_NAV_key_length])),
|
memcpy((impure->irsb_nav_data + (IPTR) rsb->rsb_arg[RSB_NAV_key_length]),
|
||||||
upper.key_data,
|
upper.key_data,
|
||||||
upper.key_length);
|
upper.key_length);
|
||||||
}
|
}
|
||||||
|
if (retrieval->irb_lower_count) {
|
||||||
// find the limit the search needs to begin with, if any
|
limit_ptr = &lower;
|
||||||
temporary_key* limit_ptr = NULL;
|
|
||||||
if (direction == RSE_get_forward)
|
|
||||||
{
|
|
||||||
if (retrieval->irb_lower_count)
|
|
||||||
limit_ptr = &lower;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (retrieval->irb_upper_count)
|
|
||||||
limit_ptr = &upper;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
|
|
||||||
// find the upper limit for the search (or lower for backwards)
|
|
||||||
temporary_key* limit_ptr = NULL;
|
|
||||||
if (direction == RSE_get_forward)
|
|
||||||
{
|
|
||||||
if (retrieval->irb_upper_count)
|
|
||||||
{
|
|
||||||
impure->irsb_nav_upper_length = upper.key_length;
|
|
||||||
memcpy((impure->irsb_nav_data + (IPTR) rsb->rsb_arg[RSB_NAV_key_length]),
|
|
||||||
upper.key_data,
|
|
||||||
upper.key_length);
|
|
||||||
}
|
|
||||||
if (retrieval->irb_lower_count) {
|
|
||||||
limit_ptr = &lower;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fb_assert(direction == RSE_get_forward);
|
|
||||||
if (retrieval->irb_lower_count)
|
|
||||||
{
|
|
||||||
impure->irsb_nav_lower_length = lower.key_length;
|
|
||||||
memcpy((impure->irsb_nav_data + (IPTR) rsb->rsb_arg[RSB_NAV_key_length]),
|
|
||||||
lower.key_data,
|
|
||||||
lower.key_length);
|
|
||||||
}
|
|
||||||
if (retrieval->irb_upper_count) {
|
|
||||||
limit_ptr = &upper;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// If there is a starting descriptor, search down index to starting position.
|
// If there is a starting descriptor, search down index to starting position.
|
||||||
// This may involve sibling buckets if splits are in progress. If there
|
// This may involve sibling buckets if splits are in progress. If there
|
||||||
// isn't a starting descriptor, walk down the left side of the index (or the
|
// isn't a starting descriptor, walk down the left side of the index.
|
||||||
// right side if backwards).
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
exp_index_buf* expanded_page = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UCHAR* pointer = NULL;
|
UCHAR* pointer = NULL;
|
||||||
if (limit_ptr)
|
if (limit_ptr)
|
||||||
@ -1110,38 +729,10 @@ static UCHAR* nav_open(thread_db* tdbb,
|
|||||||
BTreeNode::readNode(&node, pointer, page->btr_header.pag_flags, true);
|
BTreeNode::readNode(&node, pointer, page->btr_header.pag_flags, true);
|
||||||
|
|
||||||
impure->irsb_nav_length = node.prefix + node.length;
|
impure->irsb_nav_length = node.prefix + node.length;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
// ensure that if we are going backward, there is an expanded page
|
|
||||||
if (direction == RSE_get_backward && !window->win_expanded_buffer)
|
|
||||||
NAV_expand_index(window, 0);
|
|
||||||
|
|
||||||
// now find our current location on the expanded page
|
|
||||||
if (expanded_node && (expanded_page = window->win_expanded_buffer)) {
|
|
||||||
*expanded_node = find_current(expanded_page, page, pointer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
else if (direction == RSE_get_backward)
|
|
||||||
{
|
|
||||||
expanded_page = NAV_expand_index(window, 0);
|
|
||||||
pointer = BTR_last_node(page, expanded_page, expanded_node);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
pointer = BTreeNode::getPointerFirstNode(page);
|
pointer = BTreeNode::getPointerFirstNode(page);
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (expanded_node && (expanded_page = window->win_expanded_buffer)) {
|
|
||||||
*expanded_node = (btree_exp*) expanded_page->exp_nodes;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*expanded_node = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pointer;
|
return pointer;
|
||||||
|
@ -36,11 +36,7 @@ namespace Jrd {
|
|||||||
struct irsb_nav;
|
struct irsb_nav;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
bool NAV_get_record(Jrd::thread_db* tdbb, Jrd::RecordSource*, Jrd::irsb_nav*, Jrd::record_param*);
|
||||||
exp_index_buf* NAV_expand_index(Jrd::win*, Jrd::irsb_nav*);
|
|
||||||
#endif
|
|
||||||
bool NAV_get_record(Jrd::thread_db* tdbb, Jrd::RecordSource*, Jrd::irsb_nav*,
|
|
||||||
Jrd::record_param*, Jrd::rse_get_mode);
|
|
||||||
|
|
||||||
#endif // JRD_NAV_PROTO_H
|
#endif // JRD_NAV_PROTO_H
|
||||||
|
|
||||||
|
@ -111,7 +111,6 @@ NODE(nod_asn_list, asn_list, "")
|
|||||||
NODE(nod_asb, AggregateSort, "")
|
NODE(nod_asb, AggregateSort, "")
|
||||||
NODE(nod_relation, relation, "")
|
NODE(nod_relation, relation, "")
|
||||||
NODE(nod_rse, RecordSelExpr, "")
|
NODE(nod_rse, RecordSelExpr, "")
|
||||||
NODE(nod_seek, seek, "")
|
|
||||||
NODE(nod_sort, sort, "")
|
NODE(nod_sort, sort, "")
|
||||||
NODE(nod_union, union, "")
|
NODE(nod_union, union, "")
|
||||||
NODE(nod_aggregate, aggregate, "")
|
NODE(nod_aggregate, aggregate, "")
|
||||||
|
@ -130,12 +130,7 @@ static RecordSource* gen_first(thread_db*, OptimizerBlk*, RecordSource*, jrd_nod
|
|||||||
static void gen_join(thread_db*, OptimizerBlk*, const UCHAR*, RiverStack&, jrd_nod**, jrd_nod**, jrd_nod*);
|
static void gen_join(thread_db*, OptimizerBlk*, const UCHAR*, RiverStack&, jrd_nod**, jrd_nod**, jrd_nod*);
|
||||||
static RecordSource* gen_navigation(thread_db*, OptimizerBlk*, USHORT, jrd_rel*, VaryingString*,
|
static RecordSource* gen_navigation(thread_db*, OptimizerBlk*, USHORT, jrd_rel*, VaryingString*,
|
||||||
index_desc*, jrd_nod**);
|
index_desc*, jrd_nod**);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
static RecordSource* gen_nav_rsb(thread_db*, OptimizerBlk*, USHORT, jrd_rel*, VaryingString*,
|
|
||||||
index_desc*, rse_get_mode);
|
|
||||||
#else
|
|
||||||
static RecordSource* gen_nav_rsb(thread_db*, OptimizerBlk*, USHORT, jrd_rel*, VaryingString*, index_desc*);
|
static RecordSource* gen_nav_rsb(thread_db*, OptimizerBlk*, USHORT, jrd_rel*, VaryingString*, index_desc*);
|
||||||
#endif
|
|
||||||
static RecordSource* gen_outer(thread_db*, OptimizerBlk*, RecordSelExpr*, RiverStack&, jrd_nod**, jrd_nod**);
|
static RecordSource* gen_outer(thread_db*, OptimizerBlk*, RecordSelExpr*, RiverStack&, jrd_nod**, jrd_nod**);
|
||||||
static RecordSource* gen_procedure(thread_db*, OptimizerBlk*, jrd_nod*);
|
static RecordSource* gen_procedure(thread_db*, OptimizerBlk*, jrd_nod*);
|
||||||
static RecordSource* gen_residual_boolean(thread_db*, OptimizerBlk*, RecordSource*);
|
static RecordSource* gen_residual_boolean(thread_db*, OptimizerBlk*, RecordSource*);
|
||||||
@ -4527,13 +4522,7 @@ static RecordSource* gen_navigation(thread_db* tdbb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check to see if the fields in the sort match the fields in the index
|
// check to see if the fields in the sort match the fields in the index
|
||||||
// in the exact same order--we used to check for ascending/descending prior
|
// in the exact same order
|
||||||
// to SCROLLABLE_CURSORS, but now descending sorts can use ascending indices
|
|
||||||
// and vice versa.
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
rse_get_mode mode;
|
|
||||||
rse_get_mode last_mode = RSE_get_next;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
index_desc::idx_repeat* idx_tail = idx->idx_rpt;
|
index_desc::idx_repeat* idx_tail = idx->idx_rpt;
|
||||||
jrd_nod** ptr = sort->nod_arg;
|
jrd_nod** ptr = sort->nod_arg;
|
||||||
@ -4559,30 +4548,12 @@ static RecordSource* gen_navigation(thread_db* tdbb,
|
|||||||
(temp == rse_nulls_last && !ptr[sort->nod_count]))) ||
|
(temp == rse_nulls_last && !ptr[sort->nod_count]))) ||
|
||||||
// for ODS10 and earlier indices always placed nulls at the end of dataset
|
// for ODS10 and earlier indices always placed nulls at the end of dataset
|
||||||
(dbb->dbb_ods_version < ODS_VERSION11 && temp == rse_nulls_first)
|
(dbb->dbb_ods_version < ODS_VERSION11 && temp == rse_nulls_first)
|
||||||
#ifndef SCROLLABLE_CURSORS
|
|
||||||
|| (ptr[sort->nod_count] && !(idx->idx_flags & idx_descending))
|
|| (ptr[sort->nod_count] && !(idx->idx_flags & idx_descending))
|
||||||
|| (!ptr[sort->nod_count] && (idx->idx_flags & idx_descending))
|
|| (!ptr[sort->nod_count] && (idx->idx_flags & idx_descending)))
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
// determine whether we ought to navigate backwards or forwards through
|
|
||||||
// the index--we can't allow navigating one index in two different directions
|
|
||||||
// on two different fields at the same time!
|
|
||||||
mode = ((ptr[sort->nod_count] && !(idx->idx_flags & idx_descending)) ||
|
|
||||||
(!ptr[sort->nod_count] && (idx->idx_flags & idx_descending))) ?
|
|
||||||
RSE_get_backward : RSE_get_forward;
|
|
||||||
if (last_mode == RSE_get_next) {
|
|
||||||
last_mode = mode;
|
|
||||||
}
|
|
||||||
else if (last_mode != mode) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
dsc desc;
|
dsc desc;
|
||||||
CMP_get_desc(tdbb, opt->opt_csb, node, &desc);
|
CMP_get_desc(tdbb, opt->opt_csb, node, &desc);
|
||||||
|
|
||||||
@ -4603,21 +4574,13 @@ static RecordSource* gen_navigation(thread_db* tdbb,
|
|||||||
// a navigational rsb for it.
|
// a navigational rsb for it.
|
||||||
*sort_ptr = NULL;
|
*sort_ptr = NULL;
|
||||||
idx->idx_runtime_flags |= idx_navigate;
|
idx->idx_runtime_flags |= idx_navigate;
|
||||||
return gen_nav_rsb(tdbb, opt, stream, relation, alias, idx
|
return gen_nav_rsb(tdbb, opt, stream, relation, alias, idx);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, mode
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static RecordSource* gen_nav_rsb(thread_db* tdbb,
|
static RecordSource* gen_nav_rsb(thread_db* tdbb,
|
||||||
OptimizerBlk* opt,
|
OptimizerBlk* opt,
|
||||||
USHORT stream, jrd_rel* relation, VaryingString* alias, index_desc* idx
|
USHORT stream, jrd_rel* relation, VaryingString* alias, index_desc* idx)
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, rse_get_mode mode
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -4644,15 +4607,6 @@ static RecordSource* gen_nav_rsb(thread_db* tdbb,
|
|||||||
rsb->rsb_arg[RSB_NAV_index] = (RecordSource*) OPT_make_index(tdbb, opt, relation, idx);
|
rsb->rsb_arg[RSB_NAV_index] = (RecordSource*) OPT_make_index(tdbb, opt, relation, idx);
|
||||||
rsb->rsb_arg[RSB_NAV_key_length] = (RecordSource*) (IPTR) key_length;
|
rsb->rsb_arg[RSB_NAV_key_length] = (RecordSource*) (IPTR) key_length;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
// indicate that the index needs to be navigated in a mirror-image
|
|
||||||
// fashion; that when the user wants to go backwards we actually go
|
|
||||||
// forwards and vice versa
|
|
||||||
if (mode == RSE_get_backward) {
|
|
||||||
rsb->rsb_flags |= rsb_descending;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const USHORT size = OPT_nav_rsb_size(rsb, key_length, 0);
|
const USHORT size = OPT_nav_rsb_size(rsb, key_length, 0);
|
||||||
rsb->rsb_impure = CMP_impure(opt->opt_csb, size);
|
rsb->rsb_impure = CMP_impure(opt->opt_csb, size);
|
||||||
return rsb;
|
return rsb;
|
||||||
|
@ -2415,19 +2415,6 @@ static jrd_nod* par_rse(thread_db* tdbb, CompilerScratch* csb, SSHORT rse_op)
|
|||||||
rse->rse_writelock = true;
|
rse->rse_writelock = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
/* if a receive is seen here, then it is intended to be an asynchronous
|
|
||||||
receive which can happen at any time during the scope of the RecordSelExpr--
|
|
||||||
this is intended to be a more efficient mechanism for scrolling through
|
|
||||||
a record stream, to prevent having to send a message to the engine
|
|
||||||
for each record */
|
|
||||||
|
|
||||||
case blr_receive:
|
|
||||||
csb->csb_blr_reader.seekBackward(1);
|
|
||||||
rse->rse_async_message = PAR_parse_node(tdbb, csb, STATEMENT);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (op == (UCHAR) blr_end)
|
if (op == (UCHAR) blr_end)
|
||||||
{
|
{
|
||||||
@ -3038,12 +3025,15 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
|
|||||||
node->nod_arg[e_for_stall] = PAR_parse_node(tdbb, csb, STATEMENT);
|
node->nod_arg[e_for_stall] = PAR_parse_node(tdbb, csb, STATEMENT);
|
||||||
|
|
||||||
if (csb->csb_blr_reader.peekByte() == (UCHAR) blr_rse ||
|
if (csb->csb_blr_reader.peekByte() == (UCHAR) blr_rse ||
|
||||||
csb->csb_blr_reader.peekByte() == (UCHAR) blr_singular)
|
csb->csb_blr_reader.peekByte() == (UCHAR) blr_singular ||
|
||||||
|
csb->csb_blr_reader.peekByte() == (UCHAR) blr_scrollable)
|
||||||
{
|
{
|
||||||
node->nod_arg[e_for_re] = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
node->nod_arg[e_for_re] = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
node->nod_arg[e_for_re] = par_rse(tdbb, csb, blr_operator);
|
node->nod_arg[e_for_re] = par_rse(tdbb, csb, blr_operator);
|
||||||
|
}
|
||||||
node->nod_arg[e_for_statement] = PAR_parse_node(tdbb, csb, sub_type);
|
node->nod_arg[e_for_statement] = PAR_parse_node(tdbb, csb, sub_type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3070,11 +3060,11 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
|
|||||||
case blr_cursor_open:
|
case blr_cursor_open:
|
||||||
case blr_cursor_close:
|
case blr_cursor_close:
|
||||||
break;
|
break;
|
||||||
|
case blr_cursor_fetch_scroll:
|
||||||
|
node->nod_arg[e_cursor_stmt_scroll_op] = PAR_parse_node(tdbb, csb, VALUE);
|
||||||
|
node->nod_arg[e_cursor_stmt_scroll_val] = PAR_parse_node(tdbb, csb, VALUE);
|
||||||
|
// FALL INTO
|
||||||
case blr_cursor_fetch:
|
case blr_cursor_fetch:
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (csb->csb_blr_reader.peekByte() == blr_seek)
|
|
||||||
node->nod_arg[e_cursor_stmt_seek] = PAR_parse_node(tdbb, csb, STATEMENT);
|
|
||||||
#endif
|
|
||||||
csb->csb_g_flags |= csb_reuse_context;
|
csb->csb_g_flags |= csb_reuse_context;
|
||||||
node->nod_arg[e_cursor_stmt_into] = PAR_parse_node(tdbb, csb, STATEMENT);
|
node->nod_arg[e_cursor_stmt_into] = PAR_parse_node(tdbb, csb, STATEMENT);
|
||||||
csb->csb_g_flags &= ~csb_reuse_context;
|
csb->csb_g_flags &= ~csb_reuse_context;
|
||||||
@ -3094,6 +3084,11 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
|
|||||||
((RecordSelExpr*) node)->nod_flags |= rse_singular;
|
((RecordSelExpr*) node)->nod_flags |= rse_singular;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case blr_scrollable:
|
||||||
|
node = PAR_parse_node(tdbb, csb, TYPE_RSE);
|
||||||
|
((RecordSelExpr*) node)->nod_flags |= rse_scrollable;
|
||||||
|
break;
|
||||||
|
|
||||||
case blr_relation:
|
case blr_relation:
|
||||||
case blr_rid:
|
case blr_rid:
|
||||||
case blr_relation2:
|
case blr_relation2:
|
||||||
@ -3381,13 +3376,6 @@ jrd_nod* PAR_parse_node(thread_db* tdbb, CompilerScratch* csb, USHORT expected)
|
|||||||
node->nod_arg[e_stat_default] = PAR_parse_node(tdbb, csb, VALUE);
|
node->nod_arg[e_stat_default] = PAR_parse_node(tdbb, csb, VALUE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
case blr_seek:
|
|
||||||
node->nod_arg[e_seek_direction] = PAR_parse_node(tdbb, csb, VALUE);
|
|
||||||
node->nod_arg[e_seek_offset] = PAR_parse_node(tdbb, csb, VALUE);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case blr_init_variable:
|
case blr_init_variable:
|
||||||
{
|
{
|
||||||
n = csb->csb_blr_reader.getWord();
|
n = csb->csb_blr_reader.getWord();
|
||||||
|
@ -231,9 +231,6 @@ public:
|
|||||||
//vec<jrd_nod*>* req_variables; // Vector of variables, if any CVC: UNUSED
|
//vec<jrd_nod*>* req_variables; // Vector of variables, if any CVC: UNUSED
|
||||||
ResourceList req_resources; // Resources (relations and indices)
|
ResourceList req_resources; // Resources (relations and indices)
|
||||||
jrd_nod* req_message; // Current message for send/receive
|
jrd_nod* req_message; // Current message for send/receive
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
jrd_nod* req_async_message; // Asynchronous message (used in scrolling)
|
|
||||||
#endif
|
|
||||||
jrd_prc* req_procedure; // procedure, if any
|
jrd_prc* req_procedure; // procedure, if any
|
||||||
Firebird::MetaName req_trg_name; // name of request (trigger), if any
|
Firebird::MetaName req_trg_name; // name of request (trigger), if any
|
||||||
//USHORT req_length; // message length for send/receive
|
//USHORT req_length; // message length for send/receive
|
||||||
@ -338,11 +335,7 @@ const size_t REQ_SIZE = sizeof(jrd_req) - sizeof(jrd_req::blk_repeat_type);
|
|||||||
const ULONG req_active = 0x1L;
|
const ULONG req_active = 0x1L;
|
||||||
const ULONG req_stall = 0x2L;
|
const ULONG req_stall = 0x2L;
|
||||||
const ULONG req_leave = 0x4L;
|
const ULONG req_leave = 0x4L;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
const ULONG req_async_processing= 0x8L;
|
|
||||||
#endif
|
|
||||||
const ULONG req_null = 0x10L;
|
const ULONG req_null = 0x10L;
|
||||||
//const ULONG req_broken = 0x20L;
|
|
||||||
const ULONG req_abort = 0x40L;
|
const ULONG req_abort = 0x40L;
|
||||||
const ULONG req_internal = 0x80L;
|
const ULONG req_internal = 0x80L;
|
||||||
const ULONG req_warning = 0x100L;
|
const ULONG req_warning = 0x100L;
|
||||||
|
868
src/jrd/rse.cpp
868
src/jrd/rse.cpp
File diff suppressed because it is too large
Load Diff
@ -121,11 +121,10 @@ public:
|
|||||||
// bits for the rsb_flags field
|
// bits for the rsb_flags field
|
||||||
|
|
||||||
const USHORT rsb_singular = 1; // singleton select, expect 0 or 1 records
|
const USHORT rsb_singular = 1; // singleton select, expect 0 or 1 records
|
||||||
//const USHORT rsb_stream_type = 2; // rsb is for stream type request, PC_ENGINE
|
const USHORT rsb_scrollable = 2; // scrollable cursor
|
||||||
const USHORT rsb_descending = 4; // an ascending index is being used for a descending sort or vice versa
|
const USHORT rsb_project = 4; // projection on this stream is requested
|
||||||
const USHORT rsb_project = 8; // projection on this stream is requested
|
const USHORT rsb_writelock = 8; // records should be locked for writing
|
||||||
const USHORT rsb_writelock = 16; // records should be locked for writing
|
const USHORT rsb_recursive = 16; // this rsb is a sub_rsb of recursive rsb
|
||||||
const USHORT rsb_recursive = 32; // this rsb is a sub_rsb of recursive rsb
|
|
||||||
|
|
||||||
// special argument positions within the RecordSource
|
// special argument positions within the RecordSource
|
||||||
|
|
||||||
@ -298,23 +297,12 @@ const ULONG irsb_first = 1;
|
|||||||
const ULONG irsb_joined = 2; // set in left join when current record has been joined to something
|
const ULONG irsb_joined = 2; // set in left join when current record has been joined to something
|
||||||
const ULONG irsb_mustread = 4; // set in left join when must read a record from left stream
|
const ULONG irsb_mustread = 4; // set in left join when must read a record from left stream
|
||||||
const ULONG irsb_open = 8; // indicated rsb is open
|
const ULONG irsb_open = 8; // indicated rsb is open
|
||||||
#ifdef SCROLLABLE_CURSORS
|
const ULONG irsb_in_opened = 16; // set in outer join when inner stream has been opened
|
||||||
const ULONG irsb_backwards = 16; // backwards navigation has been performed on this stream
|
const ULONG irsb_join_full = 32; // set in full join when left join has completed
|
||||||
#endif
|
const ULONG irsb_checking_singular = 64; // fetching to verify singleton select
|
||||||
const ULONG irsb_in_opened = 32; // set in outer join when inner stream has been opened
|
const ULONG irsb_singular_processed = 128; // singleton stream already delivered one record
|
||||||
const ULONG irsb_join_full = 64; // set in full join when left join has completed
|
const ULONG irsb_key_changed = 256; // key has changed since record last returned from rsb
|
||||||
const ULONG irsb_checking_singular = 128; // fetching to verify singleton select
|
const ULONG irsb_eof = 512; // rsb is at end of stream
|
||||||
const ULONG irsb_singular_processed = 256; // singleton stream already delivered one record
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
const ULONG irsb_last_backwards = 512; // rsb was last scrolled in the backward direction
|
|
||||||
const ULONG irsb_bof = 1024; // rsb is at beginning of stream
|
|
||||||
const ULONG irsb_eof = 2048; // rsb is at end of stream
|
|
||||||
#endif
|
|
||||||
const ULONG irsb_key_changed = 4096; // key has changed since record last returned from rsb
|
|
||||||
// The below flag duplicates the one from the disabled SCROLLABLE_CURSORS
|
|
||||||
// implementation, but it's used slightly differently (at the top RSB levels).
|
|
||||||
// To be renamed if the SCROLLABLE_CURSORS code will ever be enabled.
|
|
||||||
const ULONG irsb_eof = 8192; // rsb is at end of stream
|
|
||||||
|
|
||||||
|
|
||||||
// Sort map block
|
// Sort map block
|
||||||
@ -462,22 +450,6 @@ public:
|
|||||||
UCHAR riv_streams[1]; // actual streams
|
UCHAR riv_streams[1]; // actual streams
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// types for navigating through a stream
|
|
||||||
|
|
||||||
enum rse_get_mode
|
|
||||||
{
|
|
||||||
RSE_get_forward
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
,
|
|
||||||
RSE_get_backward,
|
|
||||||
RSE_get_current,
|
|
||||||
RSE_get_first,
|
|
||||||
RSE_get_last,
|
|
||||||
RSE_get_next
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} //namespace Jrd
|
} //namespace Jrd
|
||||||
|
|
||||||
#endif // JRD_RSE_H
|
#endif // JRD_RSE_H
|
||||||
|
@ -34,9 +34,8 @@ namespace Jrd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RSE_close(Jrd::thread_db*, Jrd::RecordSource*);
|
void RSE_close(Jrd::thread_db*, Jrd::RecordSource*);
|
||||||
bool RSE_get_record(Jrd::thread_db*, Jrd::RecordSource*, Jrd::rse_get_mode);
|
bool RSE_get_record(Jrd::thread_db*, Jrd::RecordSource*);
|
||||||
bool RSE_internal_get_record(Jrd::thread_db*, Jrd::RecordSource*, Jrd::RecordSource*,
|
bool RSE_internal_get_record(Jrd::thread_db*, Jrd::RecordSource*, Jrd::RecordSource*);
|
||||||
Jrd::rse_get_mode);
|
|
||||||
void RSE_open(Jrd::thread_db*, Jrd::RecordSource*);
|
void RSE_open(Jrd::thread_db*, Jrd::RecordSource*);
|
||||||
|
|
||||||
#endif // JRD_RSE_PROTO_H
|
#endif // JRD_RSE_PROTO_H
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* MODULE: scroll_cursors.h
|
|
||||||
* DESCRIPTION: OSRI entrypoints and defines for SCROLLABLE_CURSORS
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Interbase Public
|
|
||||||
* License Version 1.0 (the "License"); you may not use this file
|
|
||||||
* except in compliance with the License. You may obtain a copy
|
|
||||||
* of the License at http://www.Inprise.com/IPL.html
|
|
||||||
*
|
|
||||||
* Software distributed under the License is distributed on an
|
|
||||||
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
||||||
* or implied. See the License for the specific language governing
|
|
||||||
* rights and limitations under the License.
|
|
||||||
*
|
|
||||||
* The Original Code was created by Inprise Corporation
|
|
||||||
* and its predecessors. Portions created by Inprise Corporation are
|
|
||||||
* Copyright (C) Inprise Corporation.
|
|
||||||
*
|
|
||||||
* All Rights Reserved.
|
|
||||||
* Contributor(s): ______________________________________.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef JRD_SCROLL_CURSORS_H
|
|
||||||
#define JRD_SCROLL_CURSORS_H
|
|
||||||
|
|
||||||
/* ALL THE FOLLOWING DEFINITIONS HAVE BEEN TAKEN OUT OF JRD/IBASE.H
|
|
||||||
WHEN SCROLLABLE_CURSORS ARE TOTALLY IMPLEMENTED, THE FOLLOWING
|
|
||||||
DEFINITIONS NEED TO BE PUT IN THE PROPER INCLUDE FILE.
|
|
||||||
|
|
||||||
This was done so that IB 5.0 customers do not see any functions
|
|
||||||
they are not supposed to see.
|
|
||||||
As per Engg. team's decision on 23-Sep-1997
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS ISC_EXPORT isc_dsql_fetch2(ISC_STATUS *,
|
|
||||||
isc_stmt_handle *,
|
|
||||||
unsigned short,
|
|
||||||
XSQLDA *,
|
|
||||||
unsigned short, signed long);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS ISC_EXPORT isc_dsql_fetch2_m(ISC_STATUS*,
|
|
||||||
isc_stmt_handle*,
|
|
||||||
unsigned short,
|
|
||||||
const char*,
|
|
||||||
unsigned short,
|
|
||||||
unsigned short,
|
|
||||||
char*,
|
|
||||||
unsigned short, signed long);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS ISC_EXPORT isc_embed_dsql_fetch2(ISC_STATUS*,
|
|
||||||
char*,
|
|
||||||
unsigned short,
|
|
||||||
XSQLDA*,
|
|
||||||
unsigned short, signed long);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS ISC_EXPORT isc_receive2(ISC_STATUS *,
|
|
||||||
isc_req_handle *,
|
|
||||||
short,
|
|
||||||
short,
|
|
||||||
void *,
|
|
||||||
short, unsigned short, unsigned long);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/****** Add the following commented lines in the #else part of..
|
|
||||||
#else __cplusplus || __STDC__
|
|
||||||
ISC_STATUS ISC_EXPORT isc_receive2();
|
|
||||||
******/
|
|
||||||
|
|
||||||
/****************************************/
|
|
||||||
/* Scroll direction for isc_dsql_fetch2 */
|
|
||||||
/****************************************/
|
|
||||||
|
|
||||||
const int isc_fetch_next = 0;
|
|
||||||
const int isc_fetch_prior = 1;
|
|
||||||
const int isc_fetch_first = 2;
|
|
||||||
const int isc_fetch_last = 3;
|
|
||||||
const int isc_fetch_absolute = 4;
|
|
||||||
const int isc_fetch_relative = 5;
|
|
||||||
|
|
||||||
#endif /* JRD_SCROLL_CURSORS_H */
|
|
635
src/jrd/sort.cpp
635
src/jrd/sort.cpp
@ -124,12 +124,8 @@ static ULONG high_key[] =
|
|||||||
MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG
|
MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG, MAX_ULONG
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
static sort_record* get_merge(merge_control*, sort_context*, rse_get_mode);
|
|
||||||
#else
|
|
||||||
static void diddle_key(UCHAR*, sort_context*, bool);
|
static void diddle_key(UCHAR*, sort_context*, bool);
|
||||||
static sort_record* get_merge(merge_control*, sort_context*);
|
static sort_record* get_merge(merge_control*, sort_context*);
|
||||||
#endif
|
|
||||||
|
|
||||||
static ULONG allocate_memory(sort_context*, ULONG, ULONG, bool);
|
static ULONG allocate_memory(sort_context*, ULONG, ULONG, bool);
|
||||||
static void init(sort_context*);
|
static void init(sort_context*);
|
||||||
@ -157,355 +153,6 @@ static void check_file(const sort_context*, const run_control*);
|
|||||||
|
|
||||||
static const char* const SCRATCH = "fb_sort_";
|
static const char* const SCRATCH = "fb_sort_";
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
void SORT_diddle_key(UCHAR* record, sort_context* scb, bool direction)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* S O R T _ d i d d l e _ k e y ( n o n - V A X )
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Perform transformation between the natural form of a record
|
|
||||||
* and a form that can be sorted in unsigned comparison order.
|
|
||||||
*
|
|
||||||
* direction - true for SORT_put() and false for SORT_get()
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
const sort_key_def* key = scb->scb_description;
|
|
||||||
for (const sort_key_def* const end = key + scb->scb_keys; key < end; key++)
|
|
||||||
{
|
|
||||||
UCHAR* p = record + key->skd_offset;
|
|
||||||
USHORT n = key->skd_length;
|
|
||||||
bool complement = key->skd_flags & SKD_descending;
|
|
||||||
|
|
||||||
switch (key->skd_dtype)
|
|
||||||
{
|
|
||||||
case SKD_ulong:
|
|
||||||
case SKD_ushort:
|
|
||||||
case SKD_bytes:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Stash embedded control info for non-fixed data types in the sort
|
|
||||||
// record and zap it so that it doesn't interfere with collation
|
|
||||||
|
|
||||||
case SKD_varying:
|
|
||||||
if (direction)
|
|
||||||
{
|
|
||||||
USHORT& vlen = ((vary*) p)->vary_length;
|
|
||||||
if (!(scb->scb_flags & scb_sorted))
|
|
||||||
{
|
|
||||||
*((USHORT*) (record + key->skd_vary_offset)) = vlen;
|
|
||||||
const UCHAR fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE;
|
|
||||||
UCHAR* fill_pos = p + sizeof(USHORT) + vlen;
|
|
||||||
const USHORT fill = n - sizeof(USHORT) - vlen;
|
|
||||||
if (fill)
|
|
||||||
memset(fill_pos, fill_char, fill);
|
|
||||||
}
|
|
||||||
vlen = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_cstring:
|
|
||||||
if (direction)
|
|
||||||
{
|
|
||||||
const UCHAR fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE;
|
|
||||||
if (!(scb->scb_flags & scb_sorted))
|
|
||||||
{
|
|
||||||
const USHORT l = strlen(reinterpret_cast<char*>(p));
|
|
||||||
*((USHORT*) (record + key->skd_vary_offset)) = l;
|
|
||||||
UCHAR* fill_pos = p + l;
|
|
||||||
const USHORT fill = n - l;
|
|
||||||
if (fill)
|
|
||||||
memset(fill_pos, fill_char, fill);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const USHORT l = *((USHORT*) (record + key->skd_vary_offset));
|
|
||||||
*(p + l) = fill_char;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_text:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_float:
|
|
||||||
case SKD_double:
|
|
||||||
{
|
|
||||||
const USHORT flag = (direction || !complement) ? (direction ? TRUE : FALSE) : TRUE;
|
|
||||||
if (flag ^ (*p >> 7))
|
|
||||||
*p ^= 1 << 7;
|
|
||||||
else
|
|
||||||
complement = !complement;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SKD_long:
|
|
||||||
case SKD_short:
|
|
||||||
case SKD_quad:
|
|
||||||
case SKD_timestamp1:
|
|
||||||
case SKD_timestamp2:
|
|
||||||
case SKD_sql_time:
|
|
||||||
case SKD_sql_date:
|
|
||||||
case SKD_int64:
|
|
||||||
*p ^= 1 << 7;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
fb_assert(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (complement && n)
|
|
||||||
do {
|
|
||||||
*p++ ^= -1;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
// Flatter but don't complement control info for non-fixed
|
|
||||||
// data types when restoring the data
|
|
||||||
|
|
||||||
if (key->skd_dtype == SKD_varying && !direction)
|
|
||||||
{
|
|
||||||
p = record + key->skd_offset;
|
|
||||||
((vary*) p)->vary_length = *((USHORT*) (record + key->skd_vary_offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key->skd_dtype == SKD_cstring && !direction)
|
|
||||||
{
|
|
||||||
p = record + key->skd_offset;
|
|
||||||
const USHORT l = *((USHORT*) (record + key->skd_vary_offset));
|
|
||||||
*(p + l) = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#else
|
|
||||||
void SORT_diddle_key(UCHAR* record, sort_context* scb, bool direction)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* S O R T _ d i d d l e _ k e y ( V A X )
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Perform transformation between the natural form of a record
|
|
||||||
* and a form that can be sorted in unsigned comparison order.
|
|
||||||
*
|
|
||||||
* direction - true for SORT_put() and false for SORT_get()
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
UCHAR c1;
|
|
||||||
SSHORT longs, flag;
|
|
||||||
ULONG lw;
|
|
||||||
|
|
||||||
const sort_key_def* key = scb->scb_description;
|
|
||||||
for (const sort_key_def* const end = key + scb->scb_keys; key < end; key++)
|
|
||||||
{
|
|
||||||
BLOB_PTR* p = (BLOB_PTR*) record + key->skd_offset;
|
|
||||||
USHORT* wp = (USHORT*) p;
|
|
||||||
SORTP* lwp = (SORTP*) p;
|
|
||||||
bool complement = key->skd_flags & SKD_descending;
|
|
||||||
USHORT n = ROUNDUP(key->skd_length, sizeof(SLONG));
|
|
||||||
|
|
||||||
switch (key->skd_dtype)
|
|
||||||
{
|
|
||||||
case SKD_timestamp1:
|
|
||||||
case SKD_timestamp2:
|
|
||||||
case SKD_sql_date:
|
|
||||||
case SKD_sql_time:
|
|
||||||
p[3] ^= 1 << 7;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_ulong:
|
|
||||||
case SKD_ushort:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_text:
|
|
||||||
case SKD_bytes:
|
|
||||||
case SKD_cstring:
|
|
||||||
case SKD_varying:
|
|
||||||
|
|
||||||
// Stash embedded control info for non-fixed data types in the sort
|
|
||||||
// record and zap it so that it doesn't interfere with collation
|
|
||||||
|
|
||||||
if (key->skd_dtype == SKD_varying && direction)
|
|
||||||
{
|
|
||||||
USHORT& vlen = ((vary*) p)->vary_length;
|
|
||||||
if (!(scb->scb_flags & scb_sorted))
|
|
||||||
{
|
|
||||||
*((USHORT*) (record + key->skd_vary_offset)) = vlen;
|
|
||||||
const UCHAR fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE;
|
|
||||||
UCHAR* fill_pos = p + sizeof(USHORT) + vlen;
|
|
||||||
const USHORT fill = n - sizeof(USHORT) - vlen;
|
|
||||||
if (fill)
|
|
||||||
memset(fill_pos, fill_char, fill);
|
|
||||||
}
|
|
||||||
vlen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key->skd_dtype == SKD_cstring && direction)
|
|
||||||
{
|
|
||||||
const UCHAR fill_char = (key->skd_flags & SKD_binary) ? 0 : ASCII_SPACE;
|
|
||||||
if (!(scb->scb_flags & scb_sorted))
|
|
||||||
{
|
|
||||||
const USHORT l = strlen(reinterpret_cast<char*>(p));
|
|
||||||
*((USHORT*) (record + key->skd_vary_offset)) = l;
|
|
||||||
UCHAR* fill_pos = p + l;
|
|
||||||
const USHORT fill = n - l;
|
|
||||||
if (fill)
|
|
||||||
memset(fill_pos, fill_char, fill);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USHORT l = *((USHORT*) (record + key->skd_vary_offset));
|
|
||||||
*(p + l) = fill_char;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
longs = n >> SHIFTLONG;
|
|
||||||
while (--longs >= 0)
|
|
||||||
{
|
|
||||||
c1 = p[3];
|
|
||||||
p[3] = *p;
|
|
||||||
*p++ = c1;
|
|
||||||
c1 = p[1];
|
|
||||||
p[1] = *p;
|
|
||||||
*p = c1;
|
|
||||||
p += 3;
|
|
||||||
}
|
|
||||||
p = (BLOB_PTR*) wp;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_short:
|
|
||||||
p[1] ^= 1 << 7;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_long:
|
|
||||||
p[3] ^= 1 << 7;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_quad:
|
|
||||||
p[7] ^= 1 << 7;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_int64:
|
|
||||||
|
|
||||||
// INT64's fit in TWO LONGS, and hence the SWAP has to happen
|
|
||||||
// here for the right order comparison using DO_32_COMPARE
|
|
||||||
|
|
||||||
if (!direction)
|
|
||||||
SWAP_LONGS(lwp[0], lwp[1], lw);
|
|
||||||
|
|
||||||
p[7] ^= 1 << 7;
|
|
||||||
|
|
||||||
if (direction)
|
|
||||||
SWAP_LONGS(lwp[0], lwp[1], lw);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef IEEE
|
|
||||||
case SKD_double:
|
|
||||||
if (!direction)
|
|
||||||
{
|
|
||||||
lw = lwp[0];
|
|
||||||
lwp[0] = lwp[1];
|
|
||||||
lwp[1] = lw;
|
|
||||||
}
|
|
||||||
flag = (direction || !complement) ? direction : TRUE;
|
|
||||||
if (flag ^ (p[7] >> 7))
|
|
||||||
p[7] ^= 1 << 7;
|
|
||||||
else
|
|
||||||
complement = !complement;
|
|
||||||
if (direction)
|
|
||||||
{
|
|
||||||
lw = lwp[0];
|
|
||||||
lwp[0] = lwp[1];
|
|
||||||
lwp[1] = lw;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SKD_float:
|
|
||||||
flag = (direction || !complement) ? direction : TRUE;
|
|
||||||
if (flag ^ (p[3] >> 7))
|
|
||||||
p[3] ^= 1 << 7;
|
|
||||||
else
|
|
||||||
complement = !complement;
|
|
||||||
break;
|
|
||||||
|
|
||||||
#else // IEEE
|
|
||||||
case SKD_double:
|
|
||||||
w = wp[2];
|
|
||||||
wp[2] = wp[3];
|
|
||||||
wp[3] = w;
|
|
||||||
|
|
||||||
case SKD_d_float:
|
|
||||||
case SKD_float:
|
|
||||||
if (!direction)
|
|
||||||
{
|
|
||||||
if (complement)
|
|
||||||
{
|
|
||||||
if (p[3] & 1 << 7)
|
|
||||||
complement = !complement;
|
|
||||||
else
|
|
||||||
p[3] ^= 1 << 7;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (p[3] & 1 << 7)
|
|
||||||
p[3] ^= 1 << 7;
|
|
||||||
else
|
|
||||||
complement = !complement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w = wp[0];
|
|
||||||
wp[0] = wp[1];
|
|
||||||
wp[1] = w;
|
|
||||||
if (direction)
|
|
||||||
{
|
|
||||||
if (p[3] & 1 << 7)
|
|
||||||
complement = !complement;
|
|
||||||
else
|
|
||||||
p[3] ^= 1 << 7;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif // IEEE
|
|
||||||
|
|
||||||
default:
|
|
||||||
fb_assert(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (complement && n)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
*p++ ^= -1;
|
|
||||||
} while (--n);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flatter but don't complement control info for non-fixed
|
|
||||||
// data types when restoring the data
|
|
||||||
|
|
||||||
if (key->skd_dtype == SKD_varying && !direction)
|
|
||||||
{
|
|
||||||
p = (BLOB_PTR*) record + key->skd_offset;
|
|
||||||
((vary*) p)->vary_length = *((USHORT*) (record + key->skd_vary_offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key->skd_dtype == SKD_cstring && !direction)
|
|
||||||
{
|
|
||||||
p = (BLOB_PTR*) record + key->skd_offset;
|
|
||||||
USHORT l = *((USHORT*) (record + key->skd_vary_offset));
|
|
||||||
*(p + l) = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void SORT_fini(sort_context* scb)
|
void SORT_fini(sort_context* scb)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -571,99 +218,6 @@ void SORT_fini(sort_context* scb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
void SORT_get(thread_db* tdbb, sort_context* scb, ULONG** record_address, rse_get_mode mode)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* S O R T _ g e t ( I B _ V 4 _ 1 )
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Get a record from sort (in order, of course).
|
|
||||||
* The address of the record is returned in <record_address>
|
|
||||||
* If the stream is exhausted, SORT_get puts NULL in <record_address>.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
sort_record* record = NULL;
|
|
||||||
|
|
||||||
// If there were runs, get the records from the merge
|
|
||||||
// tree. Otherwise everything fit in memory.
|
|
||||||
|
|
||||||
if (scb->scb_merge)
|
|
||||||
record = get_merge(scb->scb_merge, scb, mode);
|
|
||||||
else
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case RSE_get_forward:
|
|
||||||
if (scb->scb_flags & scb_initialized)
|
|
||||||
scb->scb_flags &= ~scb_initialized;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (scb->scb_next_pointer > scb->scb_last_pointer)
|
|
||||||
{
|
|
||||||
record = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (record = *scb->scb_next_pointer++)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RSE_get_backward:
|
|
||||||
if (scb->scb_flags & scb_initialized)
|
|
||||||
{
|
|
||||||
scb->scb_flags &= ~scb_initialized;
|
|
||||||
scb->scb_next_pointer = scb->scb_last_pointer + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// By definition, the next pointer is on the next record,
|
|
||||||
// so we have to go back one to get to the last fetched record.
|
|
||||||
// This is easier than changing the sense of the next pointer.
|
|
||||||
|
|
||||||
scb->scb_next_pointer--;
|
|
||||||
if (scb->scb_next_pointer <= scb->scb_first_pointer + 1)
|
|
||||||
{
|
|
||||||
record = NULL;
|
|
||||||
scb->scb_next_pointer++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
scb->scb_next_pointer--;
|
|
||||||
if (scb->scb_next_pointer <= scb->scb_first_pointer)
|
|
||||||
{
|
|
||||||
record = NULL;
|
|
||||||
scb->scb_next_pointer++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (record = *scb->scb_next_pointer)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset next pointer to one greater than the last fetched
|
|
||||||
|
|
||||||
scb->scb_next_pointer++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
fb_assert(FALSE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (record)
|
|
||||||
SORT_diddle_key((UCHAR*) record->sort_record_key, scb, false);
|
|
||||||
|
|
||||||
*record_address = (ULONG*) record;
|
|
||||||
|
|
||||||
tdbb->bumpStats(RuntimeStatistics::SORT_GETS);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void SORT_get(thread_db* tdbb, sort_context* scb, ULONG** record_address)
|
void SORT_get(thread_db* tdbb, sort_context* scb, ULONG** record_address)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -723,7 +277,6 @@ void SORT_get(thread_db* tdbb, sort_context* scb, ULONG** record_address)
|
|||||||
status.raise();
|
status.raise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
sort_context* SORT_init(Database* dbb,
|
sort_context* SORT_init(Database* dbb,
|
||||||
@ -884,11 +437,7 @@ void SORT_put(thread_db* tdbb, sort_context* scb, ULONG** record_address)
|
|||||||
|
|
||||||
if (record != (SR*) scb->scb_end_memory)
|
if (record != (SR*) scb->scb_end_memory)
|
||||||
{
|
{
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
SORT_diddle_key((UCHAR*) (record->sr_sort_record.sort_record_key), scb, true);
|
|
||||||
#else
|
|
||||||
diddle_key((UCHAR*) (record->sr_sort_record.sort_record_key), scb, true);
|
diddle_key((UCHAR*) (record->sr_sort_record.sort_record_key), scb, true);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there isn't room for the record, sort and write the run.
|
// If there isn't room for the record, sort and write the run.
|
||||||
@ -925,9 +474,7 @@ void SORT_put(thread_db* tdbb, sort_context* scb, ULONG** record_address)
|
|||||||
// Move key_id into *scb->scb_next_pointer and then
|
// Move key_id into *scb->scb_next_pointer and then
|
||||||
// increment scb->scb_next_pointer
|
// increment scb->scb_next_pointer
|
||||||
*scb->scb_next_pointer++ = reinterpret_cast<sort_record*>(record->sr_sort_record.sort_record_key);
|
*scb->scb_next_pointer++ = reinterpret_cast<sort_record*>(record->sr_sort_record.sort_record_key);
|
||||||
#ifndef SCROLLABLE_CURSORS
|
|
||||||
scb->scb_records++;
|
scb->scb_records++;
|
||||||
#endif
|
|
||||||
*record_address = (ULONG*) record->sr_sort_record.sort_record_key;
|
*record_address = (ULONG*) record->sr_sort_record.sort_record_key;
|
||||||
|
|
||||||
tdbb->bumpStats(RuntimeStatistics::SORT_PUTS);
|
tdbb->bumpStats(RuntimeStatistics::SORT_PUTS);
|
||||||
@ -945,12 +492,7 @@ void SORT_put(thread_db* tdbb, sort_context* scb, ULONG** record_address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
FB_UINT64 SORT_read_block(TempSpace* tmp_space, FB_UINT64 seek, BLOB_PTR* address, ULONG length)
|
||||||
void
|
|
||||||
#else
|
|
||||||
FB_UINT64
|
|
||||||
#endif
|
|
||||||
SORT_read_block(TempSpace* tmp_space, FB_UINT64 seek, BLOB_PTR* address, ULONG length)
|
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -964,9 +506,7 @@ SORT_read_block(TempSpace* tmp_space, FB_UINT64 seek, BLOB_PTR* address, ULONG l
|
|||||||
**************************************/
|
**************************************/
|
||||||
const size_t bytes = tmp_space->read(seek, address, length);
|
const size_t bytes = tmp_space->read(seek, address, length);
|
||||||
fb_assert(bytes == length);
|
fb_assert(bytes == length);
|
||||||
#ifndef SCROLLABLE_CURSORS
|
|
||||||
return seek + bytes;
|
return seek + bytes;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -993,11 +533,7 @@ void SORT_sort(thread_db* tdbb, sort_context* scb)
|
|||||||
{
|
{
|
||||||
if (scb->scb_last_record != (SR*) scb->scb_end_memory)
|
if (scb->scb_last_record != (SR*) scb->scb_end_memory)
|
||||||
{
|
{
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
SORT_diddle_key((UCHAR*) KEYOF(scb->scb_last_record), scb, true);
|
|
||||||
#else
|
|
||||||
diddle_key((UCHAR*) KEYOF(scb->scb_last_record), scb, true);
|
diddle_key((UCHAR*) KEYOF(scb->scb_last_record), scb, true);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there aren't any runs, things fit nicely in memory. Just sort the mess
|
// If there aren't any runs, things fit nicely in memory. Just sort the mess
|
||||||
@ -1005,13 +541,7 @@ void SORT_sort(thread_db* tdbb, sort_context* scb)
|
|||||||
if (!scb->scb_runs)
|
if (!scb->scb_runs)
|
||||||
{
|
{
|
||||||
sort(scb);
|
sort(scb);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
scb->scb_last_pointer = scb->scb_next_pointer - 1;
|
|
||||||
#endif
|
|
||||||
scb->scb_next_pointer = scb->scb_first_pointer + 1;
|
scb->scb_next_pointer = scb->scb_first_pointer + 1;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
scb->scb_flags |= scb_initialized;
|
|
||||||
#endif
|
|
||||||
scb->scb_flags |= scb_sorted;
|
scb->scb_flags |= scb_sorted;
|
||||||
tdbb->bumpStats(RuntimeStatistics::SORTS);
|
tdbb->bumpStats(RuntimeStatistics::SORTS);
|
||||||
return;
|
return;
|
||||||
@ -1212,7 +742,6 @@ FB_UINT64 SORT_write_block(TempSpace* tmp_space, FB_UINT64 seek, BLOB_PTR* addre
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef SCROLLABLE_CURSORS
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
static void diddle_key(UCHAR* record, sort_context* scb, bool direction)
|
static void diddle_key(UCHAR* record, sort_context* scb, bool direction)
|
||||||
{
|
{
|
||||||
@ -1559,14 +1088,9 @@ static void diddle_key(UCHAR* record, sort_context* scb, bool direction)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static sort_record* get_merge(merge_control* merge, sort_context* scb
|
static sort_record* get_merge(merge_control* merge, sort_context* scb)
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
, rse_get_mode mode
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -1581,11 +1105,7 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb
|
|||||||
SORTP *p; // no more than 1 SORTP* to a line
|
SORTP *p; // no more than 1 SORTP* to a line
|
||||||
SORTP *q; // no more than 1 SORTP* to a line
|
SORTP *q; // no more than 1 SORTP* to a line
|
||||||
ULONG l;
|
ULONG l;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ULONG space_available, data_remaining;
|
|
||||||
#else
|
|
||||||
ULONG n;
|
ULONG n;
|
||||||
#endif
|
|
||||||
|
|
||||||
sort_record* record = NULL;
|
sort_record* record = NULL;
|
||||||
bool eof = false;
|
bool eof = false;
|
||||||
@ -1601,12 +1121,7 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb
|
|||||||
|
|
||||||
// check for end-of-file condition in either direction
|
// check for end-of-file condition in either direction
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if ((mode == RSE_get_backward && run->run_records >= run->run_max_records - 1) ||
|
|
||||||
(mode == RSE_get_forward && run->run_records == 0))
|
|
||||||
#else
|
|
||||||
if (run->run_records == 0)
|
if (run->run_records == 0)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
record = (sort_record*) - 1;
|
record = (sort_record*) - 1;
|
||||||
eof = true;
|
eof = true;
|
||||||
@ -1617,83 +1132,28 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb
|
|||||||
|
|
||||||
// Find the appropriate record in the buffer to return
|
// Find the appropriate record in the buffer to return
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
if ((record = (sort_record*) run->run_record) <
|
||||||
if (mode == RSE_get_forward)
|
(sort_record*) run->run_end_buffer)
|
||||||
{
|
{
|
||||||
run->run_record = reinterpret_cast<sort_record*>(NEXT_RUN_RECORD(run->run_record));
|
run->run_record = reinterpret_cast<sort_record*>(NEXT_RUN_RECORD(run->run_record));
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((record = (sort_record*) run->run_record) <
|
|
||||||
(sort_record*) run->run_end_buffer)
|
|
||||||
{
|
|
||||||
#ifndef SCROLLABLE_CURSORS
|
|
||||||
run->run_record = reinterpret_cast<sort_record*>(NEXT_RUN_RECORD(run->run_record));
|
|
||||||
#endif
|
|
||||||
--run->run_records;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#ifndef SCROLLABLE_CURSORS
|
|
||||||
// There are records remaining, but the buffer is full.
|
|
||||||
// Read a buffer full.
|
|
||||||
|
|
||||||
l = (ULONG) ((BLOB_PTR*) run->run_end_buffer - (BLOB_PTR*) run->run_buffer);
|
|
||||||
n = run->run_records * scb->scb_longs * sizeof(ULONG);
|
|
||||||
l = MIN(l, n);
|
|
||||||
run->run_seek =
|
|
||||||
SORT_read_block(scb->scb_space, run->run_seek, (UCHAR*) run->run_buffer, l);
|
|
||||||
#else
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
run->run_record = reinterpret_cast<sort_record*>(PREV_RUN_RECORD(run->run_record));
|
|
||||||
if ((record = (sort_record*) run->run_record) >=
|
|
||||||
reinterpret_cast<sort_record*>(run->run_buffer))
|
|
||||||
{
|
|
||||||
++run->run_records;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are records remaining, but we have stepped over the
|
|
||||||
// edge of the cache. Read the next buffer full of records.
|
|
||||||
|
|
||||||
fb_assert((BLOB_PTR*) run->run_end_buffer > (BLOB_PTR*) run->run_buffer);
|
|
||||||
|
|
||||||
space_available = (ULONG) ((BLOB_PTR*) run->run_end_buffer - (BLOB_PTR*) run->run_buffer);
|
|
||||||
if (mode == RSE_get_forward)
|
|
||||||
data_remaining = run->run_records * scb->scb_longs * sizeof(ULONG);
|
|
||||||
else
|
|
||||||
data_remaining =
|
|
||||||
(run->run_max_records - run->run_records) * scb->scb_longs * sizeof(ULONG);
|
|
||||||
l = MIN(space_available, data_remaining);
|
|
||||||
|
|
||||||
if (mode == RSE_get_forward)
|
|
||||||
run->run_seek += run->run_cached;
|
|
||||||
else
|
|
||||||
run->run_seek -= l;
|
|
||||||
|
|
||||||
SORT_read_block(scb->scb_space, run->run_seek, (UCHAR*) run->run_buffer, l);
|
|
||||||
run->run_cached = l;
|
|
||||||
|
|
||||||
if (mode == RSE_get_forward)
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
record = reinterpret_cast<sort_record*>(run->run_buffer);
|
|
||||||
#ifndef SCROLLABLE_CURSORS
|
|
||||||
run->run_record =
|
|
||||||
reinterpret_cast<sort_record*>(NEXT_RUN_RECORD(record));
|
|
||||||
#endif
|
|
||||||
--run->run_records;
|
--run->run_records;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
continue;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
record = reinterpret_cast<sort_record*>(PREV_RUN_RECORD(run->run_end_buffer));
|
|
||||||
++run->run_records;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run->run_record = (sort_record*) record;
|
// There are records remaining, but the buffer is full.
|
||||||
#endif
|
// Read a buffer full.
|
||||||
|
|
||||||
|
l = (ULONG) ((BLOB_PTR*) run->run_end_buffer - (BLOB_PTR*) run->run_buffer);
|
||||||
|
n = run->run_records * scb->scb_longs * sizeof(ULONG);
|
||||||
|
l = MIN(l, n);
|
||||||
|
run->run_seek =
|
||||||
|
SORT_read_block(scb->scb_space, run->run_seek, (UCHAR*) run->run_buffer, l);
|
||||||
|
|
||||||
|
record = reinterpret_cast<sort_record*>(run->run_buffer);
|
||||||
|
run->run_record =
|
||||||
|
reinterpret_cast<sort_record*>(NEXT_RUN_RECORD(record));
|
||||||
|
--run->run_records;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1766,32 +1226,19 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb
|
|||||||
|
|
||||||
if (l == 0 && scb->scb_dup_callback)
|
if (l == 0 && scb->scb_dup_callback)
|
||||||
{
|
{
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
SORT_diddle_key((UCHAR*) merge->mrg_record_a, scb, false);
|
|
||||||
SORT_diddle_key((UCHAR*) merge->mrg_record_b, scb, false);
|
|
||||||
#else
|
|
||||||
diddle_key((UCHAR*) merge->mrg_record_a, scb, false);
|
diddle_key((UCHAR*) merge->mrg_record_a, scb, false);
|
||||||
diddle_key((UCHAR*) merge->mrg_record_b, scb, false);
|
diddle_key((UCHAR*) merge->mrg_record_b, scb, false);
|
||||||
#endif
|
|
||||||
if ((*scb->scb_dup_callback) ((const UCHAR*) merge->mrg_record_a,
|
if ((*scb->scb_dup_callback) ((const UCHAR*) merge->mrg_record_a,
|
||||||
(const UCHAR*) merge->mrg_record_b,
|
(const UCHAR*) merge->mrg_record_b,
|
||||||
scb->scb_dup_callback_arg))
|
scb->scb_dup_callback_arg))
|
||||||
{
|
{
|
||||||
merge->mrg_record_a = NULL;
|
merge->mrg_record_a = NULL;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
SORT_diddle_key((UCHAR*) merge->mrg_record_b, scb, true);
|
|
||||||
#else
|
|
||||||
diddle_key((UCHAR*) merge->mrg_record_b, scb, true);
|
diddle_key((UCHAR*) merge->mrg_record_b, scb, true);
|
||||||
#endif
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
SORT_diddle_key((UCHAR*) merge->mrg_record_a, scb, true);
|
|
||||||
SORT_diddle_key((UCHAR*) merge->mrg_record_b, scb, true);
|
|
||||||
#else
|
|
||||||
diddle_key((UCHAR*) merge->mrg_record_a, scb, true);
|
diddle_key((UCHAR*) merge->mrg_record_a, scb, true);
|
||||||
diddle_key((UCHAR*) merge->mrg_record_b, scb, true);
|
diddle_key((UCHAR*) merge->mrg_record_b, scb, true);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l == 0)
|
if (l == 0)
|
||||||
@ -1801,11 +1248,7 @@ static sort_record* get_merge(merge_control* merge, sort_context* scb
|
|||||||
DO_32_COMPARE(p, q, l);
|
DO_32_COMPARE(p, q, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
if (mode == RSE_get_forward && p[-1] < q[-1])
|
|
||||||
#else
|
|
||||||
if (p[-1] < q[-1])
|
if (p[-1] < q[-1])
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
record = merge->mrg_record_a;
|
record = merge->mrg_record_a;
|
||||||
merge->mrg_record_a = NULL;
|
merge->mrg_record_a = NULL;
|
||||||
@ -2110,11 +1553,7 @@ static void merge_runs(sort_context* scb, USHORT n)
|
|||||||
CHECK_FILE2(scb, &temp_run);
|
CHECK_FILE2(scb, &temp_run);
|
||||||
|
|
||||||
const sort_record* p;
|
const sort_record* p;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
while (p = get_merge(merge, scb, RSE_get_forward))
|
|
||||||
#else
|
|
||||||
while ( (p = get_merge(merge, scb)) )
|
while ( (p = get_merge(merge, scb)) )
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
if (q >= (sort_record*) temp_run.run_end_buffer)
|
if (q >= (sort_record*) temp_run.run_end_buffer)
|
||||||
{
|
{
|
||||||
@ -2128,9 +1567,6 @@ static void merge_runs(sort_context* scb, USHORT n)
|
|||||||
} while (--count);
|
} while (--count);
|
||||||
++temp_run.run_records;
|
++temp_run.run_records;
|
||||||
}
|
}
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
temp_run.run_max_records = temp_run.run_records;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Write the tail of the new run and return any unused space
|
// Write the tail of the new run and return any unused space
|
||||||
|
|
||||||
@ -2153,11 +1589,8 @@ static void merge_runs(sort_context* scb, USHORT n)
|
|||||||
// Remove run from list of in-use run blocks
|
// Remove run from list of in-use run blocks
|
||||||
run = scb->scb_runs;
|
run = scb->scb_runs;
|
||||||
scb->scb_runs = run->run_next;
|
scb->scb_runs = run->run_next;
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
seek = run->run_seek + run->run_cached - run->run_size;
|
|
||||||
#else
|
|
||||||
seek = run->run_seek - run->run_size;
|
seek = run->run_seek - run->run_size;
|
||||||
#endif
|
|
||||||
// Free the sort file space associated with the run
|
// Free the sort file space associated with the run
|
||||||
|
|
||||||
scb->scb_space->releaseSpace(seek, run->run_size);
|
scb->scb_space->releaseSpace(seek, run->run_size);
|
||||||
@ -2546,19 +1979,7 @@ static void put_run(sort_context* scb)
|
|||||||
// Re-arrange records in physical order so they can be dumped in a single write
|
// Re-arrange records in physical order so they can be dumped in a single write
|
||||||
// operation
|
// operation
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
run->run_records = run->run_max_records = order(scb);
|
|
||||||
run->run_cached = 0;
|
|
||||||
|
|
||||||
// Write records to scratch file. Keep track of the number of bytes
|
|
||||||
// written, etc.
|
|
||||||
|
|
||||||
run->run_size = run->run_records * (scb->scb_longs - SIZEOF_SR_BCKPTR_IN_LONGS) * sizeof(ULONG);
|
|
||||||
run->run_seek = scb->scb_space->allocateSpace(run->run_size);
|
|
||||||
SORT_write_block(scb->scb_space, run->run_seek, (UCHAR*) scb->scb_last_record, run->run_size);
|
|
||||||
#else
|
|
||||||
order_and_save(scb);
|
order_and_save(scb);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2642,26 +2063,20 @@ static void sort(sort_context* scb)
|
|||||||
DO_32_COMPARE(p, q, l);
|
DO_32_COMPARE(p, q, l);
|
||||||
if (l == 0)
|
if (l == 0)
|
||||||
{
|
{
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
SORT_diddle_key((UCHAR*) *i, scb, false);
|
|
||||||
SORT_diddle_key((UCHAR*) *j, scb, false);
|
|
||||||
#else
|
|
||||||
diddle_key((UCHAR*) *i, scb, false);
|
diddle_key((UCHAR*) *i, scb, false);
|
||||||
diddle_key((UCHAR*) *j, scb, false);
|
diddle_key((UCHAR*) *j, scb, false);
|
||||||
#endif
|
|
||||||
if ((*scb->scb_dup_callback) ((const UCHAR*) *i, (const UCHAR*) *j, scb->scb_dup_callback_arg))
|
if ((*scb->scb_dup_callback) ((const UCHAR*) *i, (const UCHAR*) *j, scb->scb_dup_callback_arg))
|
||||||
{
|
{
|
||||||
((SORTP***) (*i))[BACK_OFFSET] = NULL;
|
((SORTP***) (*i))[BACK_OFFSET] = NULL;
|
||||||
*i = NULL;
|
*i = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#ifdef SCROLLABLE_CURSORS
|
{
|
||||||
SORT_diddle_key((UCHAR*) *i, scb, true);
|
|
||||||
SORT_diddle_key((UCHAR*) *j, scb, true);
|
|
||||||
#else
|
|
||||||
diddle_key((UCHAR*) *i, scb, true);
|
diddle_key((UCHAR*) *i, scb, true);
|
||||||
|
}
|
||||||
|
|
||||||
diddle_key((UCHAR*) *j, scb, true);
|
diddle_key((UCHAR*) *j, scb, true);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,15 +196,9 @@ struct run_control
|
|||||||
run_merge_hdr run_header;
|
run_merge_hdr run_header;
|
||||||
run_control* run_next; // Next (actually last) run
|
run_control* run_next; // Next (actually last) run
|
||||||
ULONG run_records; // Records (remaining) in run
|
ULONG run_records; // Records (remaining) in run
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ULONG run_max_records; // total number of records in run
|
|
||||||
#endif
|
|
||||||
USHORT run_depth; // Number of "elementary" runs
|
USHORT run_depth; // Number of "elementary" runs
|
||||||
FB_UINT64 run_seek; // Offset in file of run
|
FB_UINT64 run_seek; // Offset in file of run
|
||||||
FB_UINT64 run_size; // Length of run in work file
|
FB_UINT64 run_size; // Length of run in work file
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
FB_UINT64 run_cached; // amount of cached data from run file
|
|
||||||
#endif
|
|
||||||
sort_record* run_record; // Next record in run
|
sort_record* run_record; // Next record in run
|
||||||
SORTP* run_buffer; // Run buffer
|
SORTP* run_buffer; // Run buffer
|
||||||
SORTP* run_end_buffer; // End of buffer
|
SORTP* run_end_buffer; // End of buffer
|
||||||
@ -242,9 +236,6 @@ struct sort_context
|
|||||||
SR* scb_last_record; // Address of last record
|
SR* scb_last_record; // Address of last record
|
||||||
sort_record** scb_first_pointer; // Memory for sort
|
sort_record** scb_first_pointer; // Memory for sort
|
||||||
sort_record** scb_next_pointer; // Address for next pointer
|
sort_record** scb_next_pointer; // Address for next pointer
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
sort_record** scb_last_pointer; // Address for last pointer in block
|
|
||||||
#endif
|
|
||||||
//USHORT scb_length; // Record length. Unused.
|
//USHORT scb_length; // Record length. Unused.
|
||||||
USHORT scb_longs; // Length of record in longwords
|
USHORT scb_longs; // Length of record in longwords
|
||||||
ULONG scb_keys; // Number of keys
|
ULONG scb_keys; // Number of keys
|
||||||
|
@ -32,15 +32,8 @@ namespace Jrd {
|
|||||||
class SortOwner;
|
class SortOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
void SORT_diddle_key(UCHAR*, Jrd::sort_context*, bool);
|
|
||||||
void SORT_get(Jrd::thread_db*, Jrd::sort_context*, ULONG**, Jrd::rse_get_mode);
|
|
||||||
void SORT_read_block(TempSpace*, FB_UINT64, BLOB_PTR*, ULONG);
|
|
||||||
#else
|
|
||||||
void SORT_get(Jrd::thread_db*, Jrd::sort_context*, ULONG**);
|
void SORT_get(Jrd::thread_db*, Jrd::sort_context*, ULONG**);
|
||||||
FB_UINT64 SORT_read_block(TempSpace*, FB_UINT64, BLOB_PTR*, ULONG);
|
FB_UINT64 SORT_read_block(TempSpace*, FB_UINT64, BLOB_PTR*, ULONG);
|
||||||
#endif
|
|
||||||
|
|
||||||
void SORT_fini(Jrd::sort_context*);
|
void SORT_fini(Jrd::sort_context*);
|
||||||
Jrd::sort_context* SORT_init(Jrd::Database*, Jrd::SortOwner*,
|
Jrd::sort_context* SORT_init(Jrd::Database*, Jrd::SortOwner*,
|
||||||
USHORT, USHORT, USHORT, const Jrd::sort_key_def*,
|
USHORT, USHORT, USHORT, const Jrd::sort_key_def*,
|
||||||
|
@ -941,7 +941,6 @@ static void garbage_collect(thread_db* tdbb, vdr* control)
|
|||||||
// Dump verbose output of all the pages fetched
|
// Dump verbose output of all the pages fetched
|
||||||
if (VAL_debug_level >= 2)
|
if (VAL_debug_level >= 2)
|
||||||
{
|
{
|
||||||
// We are assuming RSE_get_forward
|
|
||||||
if (control->vdr_page_bitmap->getFirst())
|
if (control->vdr_page_bitmap->getFirst())
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
|
@ -2454,9 +2454,6 @@ bool VIO_next_record(thread_db* tdbb,
|
|||||||
//RecordSource* rsb,
|
//RecordSource* rsb,
|
||||||
jrd_tra* transaction,
|
jrd_tra* transaction,
|
||||||
MemoryPool* pool,
|
MemoryPool* pool,
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
bool backwards,
|
|
||||||
#endif
|
|
||||||
bool onepage)
|
bool onepage)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
@ -2496,11 +2493,7 @@ bool VIO_next_record(thread_db* tdbb,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!DPM_next(tdbb, rpb, lock_type,
|
if (!DPM_next(tdbb, rpb, lock_type, onepage))
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
backwards,
|
|
||||||
#endif
|
|
||||||
onepage))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2948,11 +2941,7 @@ bool VIO_sweep(thread_db* tdbb, jrd_tra* transaction)
|
|||||||
relation->rel_garbage->clear();
|
relation->rel_garbage->clear();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
while (VIO_next_record(tdbb, &rpb, /*NULL,*/ transaction, 0,
|
while (VIO_next_record(tdbb, &rpb, /*NULL,*/ transaction, 0, false))
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
false,
|
|
||||||
#endif
|
|
||||||
false))
|
|
||||||
{
|
{
|
||||||
CCH_RELEASE(tdbb, &rpb.getWindow(tdbb));
|
CCH_RELEASE(tdbb, &rpb.getWindow(tdbb));
|
||||||
if (relation->rel_flags & REL_deleting) {
|
if (relation->rel_flags & REL_deleting) {
|
||||||
@ -4075,11 +4064,7 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
|
|||||||
|
|
||||||
// Attempt to garbage collect all records on the data page.
|
// Attempt to garbage collect all records on the data page.
|
||||||
|
|
||||||
while (VIO_next_record(tdbb, &rpb, /*NULL,*/ transaction, NULL,
|
while (VIO_next_record(tdbb, &rpb, /*NULL,*/ transaction, NULL, true))
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
false,
|
|
||||||
#endif
|
|
||||||
true))
|
|
||||||
{
|
{
|
||||||
CCH_RELEASE(tdbb, &rpb.getWindow(tdbb));
|
CCH_RELEASE(tdbb, &rpb.getWindow(tdbb));
|
||||||
|
|
||||||
|
@ -57,11 +57,7 @@ void VIO_merge_proc_sav_points(Jrd::thread_db*, Jrd::jrd_tra*, Jrd::Savepoint**)
|
|||||||
bool VIO_writelock(Jrd::thread_db*, Jrd::record_param*, Jrd::RecordSource*, Jrd::jrd_tra*);
|
bool VIO_writelock(Jrd::thread_db*, Jrd::record_param*, Jrd::RecordSource*, Jrd::jrd_tra*);
|
||||||
void VIO_modify(Jrd::thread_db*, Jrd::record_param*, Jrd::record_param*, Jrd::jrd_tra*);
|
void VIO_modify(Jrd::thread_db*, Jrd::record_param*, Jrd::record_param*, Jrd::jrd_tra*);
|
||||||
bool VIO_next_record(Jrd::thread_db*, Jrd::record_param*, /*Jrd::RecordSource*,*/ Jrd::jrd_tra*,
|
bool VIO_next_record(Jrd::thread_db*, Jrd::record_param*, /*Jrd::RecordSource*,*/ Jrd::jrd_tra*,
|
||||||
MemoryPool*,
|
MemoryPool*, bool);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
bool,
|
|
||||||
#endif
|
|
||||||
bool);
|
|
||||||
Jrd::Record* VIO_record(Jrd::thread_db*, Jrd::record_param*, const Jrd::Format*, MemoryPool*);
|
Jrd::Record* VIO_record(Jrd::thread_db*, Jrd::record_param*, const Jrd::Format*, MemoryPool*);
|
||||||
void VIO_refetch_record(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*);
|
void VIO_refetch_record(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*);
|
||||||
void VIO_start_save_point(Jrd::thread_db*, Jrd::jrd_tra*);
|
void VIO_start_save_point(Jrd::thread_db*, Jrd::jrd_tra*);
|
||||||
|
178
src/jrd/why.cpp
178
src/jrd/why.cpp
@ -96,9 +96,6 @@
|
|||||||
#include "../common/classes/FpeControl.h"
|
#include "../common/classes/FpeControl.h"
|
||||||
#include "../jrd/constants.h"
|
#include "../jrd/constants.h"
|
||||||
#include "../jrd/ThreadStart.h"
|
#include "../jrd/ThreadStart.h"
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
#include "../jrd/blr.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ERRNO_H
|
#ifdef HAVE_ERRNO_H
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -1089,11 +1086,6 @@ namespace
|
|||||||
#define GDS_QUE_EVENTS isc_que_events
|
#define GDS_QUE_EVENTS isc_que_events
|
||||||
#define GDS_RECONNECT isc_reconnect_transaction
|
#define GDS_RECONNECT isc_reconnect_transaction
|
||||||
#define GDS_RECEIVE isc_receive
|
#define GDS_RECEIVE isc_receive
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
#define GDS_RECEIVE2 isc_receive2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define GDS_RELEASE_REQUEST isc_release_request
|
#define GDS_RELEASE_REQUEST isc_release_request
|
||||||
#define GDS_REQUEST_INFO isc_request_info
|
#define GDS_REQUEST_INFO isc_request_info
|
||||||
#define GDS_ROLLBACK isc_rollback_transaction
|
#define GDS_ROLLBACK isc_rollback_transaction
|
||||||
@ -3155,71 +3147,6 @@ ISC_STATUS API_ROUTINE GDS_DSQL_FETCH(ISC_STATUS* user_status,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS API_ROUTINE GDS_DSQL_FETCH2(ISC_STATUS* user_status,
|
|
||||||
FB_API_HANDLE* stmt_handle,
|
|
||||||
USHORT dialect,
|
|
||||||
XSQLDA* sqlda,
|
|
||||||
USHORT direction,
|
|
||||||
SLONG offset)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* i s c _ d s q l _ f e t c h 2
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Fetch next record from a dynamic SQL cursor
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
Status status(user_status);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!sqlda)
|
|
||||||
{
|
|
||||||
status_exception::raise(Arg::Gds(isc_dsql_sqlda_err));
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement statement = translate<CStatement>(stmt_handle);
|
|
||||||
|
|
||||||
statement->checkPrepared();
|
|
||||||
sqlda_sup& dasup = statement->das;
|
|
||||||
|
|
||||||
USHORT blr_length, msg_type, msg_length;
|
|
||||||
|
|
||||||
if (UTLD_parse_sqlda(status, &dasup, &blr_length, &msg_type, &msg_length,
|
|
||||||
dialect, sqlda, DASUP_CLAUSE_select))
|
|
||||||
{
|
|
||||||
return status[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
ISC_STATUS s = GDS_DSQL_FETCH2_M(status, stmt_handle, blr_length,
|
|
||||||
dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_blr,
|
|
||||||
0, msg_length,
|
|
||||||
dasup.dasup_clauses[DASUP_CLAUSE_select].dasup_msg,
|
|
||||||
direction, offset);
|
|
||||||
if (s && s != 101)
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UTLD_parse_sqlda(status, &dasup, NULL, NULL, NULL, dialect, sqlda, DASUP_CLAUSE_select))
|
|
||||||
{
|
|
||||||
return status[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const Exception& e)
|
|
||||||
{
|
|
||||||
e.stuff_exception(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status[1];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
ISC_STATUS API_ROUTINE GDS_DSQL_FETCH_M(ISC_STATUS* user_status,
|
ISC_STATUS API_ROUTINE GDS_DSQL_FETCH_M(ISC_STATUS* user_status,
|
||||||
FB_API_HANDLE* stmt_handle,
|
FB_API_HANDLE* stmt_handle,
|
||||||
USHORT blr_length,
|
USHORT blr_length,
|
||||||
@ -3248,12 +3175,7 @@ ISC_STATUS API_ROUTINE GDS_DSQL_FETCH_M(ISC_STATUS* user_status,
|
|||||||
ISC_STATUS s =
|
ISC_STATUS s =
|
||||||
CALL(PROC_DSQL_FETCH, statement->implementation) (status, &statement->handle,
|
CALL(PROC_DSQL_FETCH, statement->implementation) (status, &statement->handle,
|
||||||
blr_length, blr,
|
blr_length, blr,
|
||||||
msg_type, msg_length, msg
|
msg_type, msg_length, msg);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
,
|
|
||||||
(USHORT) 0, (ULONG) 1
|
|
||||||
#endif // SCROLLABLE_CURSORS
|
|
||||||
);
|
|
||||||
|
|
||||||
if (s == 100 || s == 101)
|
if (s == 100 || s == 101)
|
||||||
{
|
{
|
||||||
@ -3269,55 +3191,6 @@ ISC_STATUS API_ROUTINE GDS_DSQL_FETCH_M(ISC_STATUS* user_status,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS API_ROUTINE GDS_DSQL_FETCH2_M(ISC_STATUS* user_status,
|
|
||||||
FB_API_HANDLE* stmt_handle,
|
|
||||||
USHORT blr_length,
|
|
||||||
SCHAR* blr,
|
|
||||||
USHORT msg_type,
|
|
||||||
USHORT msg_length,
|
|
||||||
SCHAR* msg,
|
|
||||||
USHORT direction,
|
|
||||||
SLONG offset)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* i s c _ d s q l _ f e t c h 2 _ m
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Fetch next record from a dynamic SQL cursor
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
Status status(user_status);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Statement statement = translate<CStatement>(stmt_handle);
|
|
||||||
YEntry entryGuard(statement);
|
|
||||||
|
|
||||||
ISC_STATUS s =
|
|
||||||
CALL(PROC_DSQL_FETCH, statement->implementation) (status, &statement->handle,
|
|
||||||
blr_length, blr,
|
|
||||||
msg_type, msg_length, msg,
|
|
||||||
direction, offset);
|
|
||||||
|
|
||||||
if (s == 100 || s == 101)
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const Exception& e)
|
|
||||||
{
|
|
||||||
e.stuff_exception(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status[1];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
ISC_STATUS API_ROUTINE GDS_DSQL_FREE(ISC_STATUS* user_status,
|
ISC_STATUS API_ROUTINE GDS_DSQL_FREE(ISC_STATUS* user_status,
|
||||||
FB_API_HANDLE* stmt_handle,
|
FB_API_HANDLE* stmt_handle,
|
||||||
USHORT option)
|
USHORT option)
|
||||||
@ -4161,12 +4034,6 @@ ISC_STATUS API_ROUTINE GDS_RECEIVE(ISC_STATUS* user_status,
|
|||||||
* Get a record from the host program.
|
* Get a record from the host program.
|
||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
return GDS_RECEIVE2(user_status, req_handle, msg_type, msg_length,
|
|
||||||
msg, level, (USHORT) blr_continue, /* means continue in same direction as before */
|
|
||||||
(ULONG) 1);
|
|
||||||
#else
|
|
||||||
Status status(user_status);
|
Status status(user_status);
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -4184,52 +4051,9 @@ ISC_STATUS API_ROUTINE GDS_RECEIVE(ISC_STATUS* user_status,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return status[1];
|
return status[1];
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS API_ROUTINE GDS_RECEIVE2(ISC_STATUS* user_status,
|
|
||||||
FB_API_HANDLE* req_handle,
|
|
||||||
USHORT msg_type,
|
|
||||||
USHORT msg_length,
|
|
||||||
SCHAR* msg,
|
|
||||||
SSHORT level,
|
|
||||||
USHORT direction,
|
|
||||||
ULONG offset)
|
|
||||||
{
|
|
||||||
/**************************************
|
|
||||||
*
|
|
||||||
* i s c _ r e c e i v e 2
|
|
||||||
*
|
|
||||||
**************************************
|
|
||||||
*
|
|
||||||
* Functional description
|
|
||||||
* Scroll through the request output stream,
|
|
||||||
* then get a record from the host program.
|
|
||||||
*
|
|
||||||
**************************************/
|
|
||||||
Status status(user_status);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Request request = translate<CRequest>(req_handle);
|
|
||||||
YEntry entryGuard(request);
|
|
||||||
|
|
||||||
CALL(PROC_RECEIVE, request->implementation) (status, &request->handle,
|
|
||||||
msg_type, msg_length, msg,
|
|
||||||
level, direction, offset);
|
|
||||||
}
|
|
||||||
catch (const Exception& e)
|
|
||||||
{
|
|
||||||
e.stuff_exception(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status[1];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
ISC_STATUS API_ROUTINE GDS_RECONNECT(ISC_STATUS* user_status,
|
ISC_STATUS API_ROUTINE GDS_RECONNECT(ISC_STATUS* user_status,
|
||||||
FB_API_HANDLE* db_handle,
|
FB_API_HANDLE* db_handle,
|
||||||
FB_API_HANDLE* tra_handle,
|
FB_API_HANDLE* tra_handle,
|
||||||
|
@ -74,17 +74,8 @@ ISC_STATUS API_ROUTINE isc_dsql_exec_immed3_m(ISC_STATUS*, FB_API_HANDLE*,
|
|||||||
const SCHAR*, USHORT, SCHAR*,
|
const SCHAR*, USHORT, SCHAR*,
|
||||||
USHORT, USHORT, SCHAR*);
|
USHORT, USHORT, SCHAR*);
|
||||||
ISC_STATUS API_ROUTINE isc_dsql_fetch(ISC_STATUS*, FB_API_HANDLE*, USHORT, const XSQLDA*);
|
ISC_STATUS API_ROUTINE isc_dsql_fetch(ISC_STATUS*, FB_API_HANDLE*, USHORT, const XSQLDA*);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS API_ROUTINE isc_dsql_fetch2(ISC_STATUS*, FB_API_HANDLE*, USHORT,
|
|
||||||
XSQLDA*, USHORT, SLONG);
|
|
||||||
#endif
|
|
||||||
ISC_STATUS API_ROUTINE isc_dsql_fetch_m(ISC_STATUS*, FB_API_HANDLE*, USHORT,
|
ISC_STATUS API_ROUTINE isc_dsql_fetch_m(ISC_STATUS*, FB_API_HANDLE*, USHORT,
|
||||||
SCHAR*, USHORT, USHORT, SCHAR*);
|
SCHAR*, USHORT, USHORT, SCHAR*);
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS API_ROUTINE isc_dsql_fetch2_m(ISC_STATUS*, FB_API_HANDLE*, USHORT,
|
|
||||||
SCHAR*, USHORT, USHORT, SCHAR*,
|
|
||||||
USHORT, SLONG);
|
|
||||||
#endif
|
|
||||||
ISC_STATUS API_ROUTINE isc_dsql_free_statement(ISC_STATUS*, FB_API_HANDLE*, USHORT);
|
ISC_STATUS API_ROUTINE isc_dsql_free_statement(ISC_STATUS*, FB_API_HANDLE*, USHORT);
|
||||||
ISC_STATUS API_ROUTINE isc_dsql_insert(ISC_STATUS*, FB_API_HANDLE*, USHORT, XSQLDA*);
|
ISC_STATUS API_ROUTINE isc_dsql_insert(ISC_STATUS*, FB_API_HANDLE*, USHORT, XSQLDA*);
|
||||||
ISC_STATUS API_ROUTINE isc_dsql_insert_m(ISC_STATUS*, FB_API_HANDLE*, USHORT,
|
ISC_STATUS API_ROUTINE isc_dsql_insert_m(ISC_STATUS*, FB_API_HANDLE*, USHORT,
|
||||||
@ -108,11 +99,6 @@ ISC_STATUS API_ROUTINE isc_dsql_sql_info(ISC_STATUS*, FB_API_HANDLE*, SSHORT,
|
|||||||
//ISC_STATUS API_ROUTINE isc_que_events(ISC_STATUS*, FB_API_HANDLE*, SLONG*,
|
//ISC_STATUS API_ROUTINE isc_que_events(ISC_STATUS*, FB_API_HANDLE*, SLONG*,
|
||||||
// USHORT, const UCHAR*,
|
// USHORT, const UCHAR*,
|
||||||
// FPTR_EVENT_CALLBACK, void*);
|
// FPTR_EVENT_CALLBACK, void*);
|
||||||
//#ifdef SCROLLABLE_CURSORS
|
|
||||||
//ISC_STATUS API_ROUTINE isc_receive2(ISC_STATUS*, FB_API_HANDLE*, USHORT,
|
|
||||||
// USHORT, SCHAR*, SSHORT, USHORT,
|
|
||||||
// ULONG);
|
|
||||||
//#endif
|
|
||||||
//ISC_STATUS API_ROUTINE isc_rollback_transaction(ISC_STATUS*, FB_API_HANDLE*);
|
//ISC_STATUS API_ROUTINE isc_rollback_transaction(ISC_STATUS*, FB_API_HANDLE*);
|
||||||
//ISC_STATUS API_ROUTINE_VARARG isc_start_transaction(ISC_STATUS*,
|
//ISC_STATUS API_ROUTINE_VARARG isc_start_transaction(ISC_STATUS*,
|
||||||
// FB_API_HANDLE*, SSHORT,
|
// FB_API_HANDLE*, SSHORT,
|
||||||
@ -191,11 +177,6 @@ ISC_STATUS API_ROUTINE isc_que_events(ISC_STATUS*, FB_API_HANDLE*, SLONG*, USHOR
|
|||||||
ISC_STATUS API_ROUTINE isc_receive(ISC_STATUS*, FB_API_HANDLE*, USHORT, USHORT,
|
ISC_STATUS API_ROUTINE isc_receive(ISC_STATUS*, FB_API_HANDLE*, USHORT, USHORT,
|
||||||
SCHAR*, SSHORT);
|
SCHAR*, SSHORT);
|
||||||
|
|
||||||
#ifdef SCROLLABLE_CURSORS
|
|
||||||
ISC_STATUS API_ROUTINE isc_receive2(ISC_STATUS*, FB_API_HANDLE*, USHORT, USHORT, SCHAR*,
|
|
||||||
SSHORT, USHORT, ULONG);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ISC_STATUS API_ROUTINE isc_reconnect_transaction(ISC_STATUS*, FB_API_HANDLE*, FB_API_HANDLE*,
|
ISC_STATUS API_ROUTINE isc_reconnect_transaction(ISC_STATUS*, FB_API_HANDLE*, FB_API_HANDLE*,
|
||||||
SSHORT, const UCHAR*);
|
SSHORT, const UCHAR*);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user