8
0
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:
dimitr 2009-10-31 06:25:01 +00:00
parent 136b6013fc
commit e6909de7f7
37 changed files with 255 additions and 3189 deletions

View File

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

View File

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

View File

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

View File

@ -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)
{ {
/************************************** /**************************************

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
{ {
/************************************** /**************************************

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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