2003-12-01 11:25:41 +01:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
|
|
|
* MODULE: btn.cpp
|
|
|
|
* DESCRIPTION: B-tree management code
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Initial
|
|
|
|
* Developer's Public License Version 1.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the
|
|
|
|
* License. You may obtain a copy of the License at
|
|
|
|
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed AS IS,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing rights
|
|
|
|
* and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code was created by Arno Brinkman
|
|
|
|
* for the Firebird Open Source RDBMS project.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003 Arno Brinkman and all contributors
|
|
|
|
* signed below.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "firebird.h" // needed for get_long
|
|
|
|
#include "memory_routines.h" // needed for get_long
|
|
|
|
|
|
|
|
#include "../jrd/common.h" // needed for SINT64
|
|
|
|
#include "../jrd/ods.h"
|
|
|
|
#include "../jrd/btn.h"
|
|
|
|
|
|
|
|
namespace BTreeNode {
|
|
|
|
|
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
USHORT computePrefix(const UCHAR* prevString, USHORT prevLength,
|
|
|
|
const UCHAR* string, USHORT length)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c o m p u t e P r e f i x
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Compute and return prefix common
|
|
|
|
* to two strings.
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-03 09:44:28 +01:00
|
|
|
USHORT l = MIN(prevLength, length);
|
|
|
|
if (!l) {
|
2003-12-01 11:25:41 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
const UCHAR* p = prevString;
|
2003-12-01 11:25:41 +01:00
|
|
|
|
|
|
|
while (*p == *string) {
|
2003-12-03 09:44:28 +01:00
|
|
|
++p;
|
|
|
|
++string;
|
2003-12-01 11:25:41 +01:00
|
|
|
if (!--l) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (p - prevString);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
SLONG findPageInDuplicates(const btree_page* page, UCHAR* pointer,
|
2003-12-01 11:25:41 +01:00
|
|
|
SLONG previousNumber, SLONG findRecordNumber)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* f i n d P a g e I n D u p l i c a t e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Return the first page number
|
|
|
|
*
|
|
|
|
**************************************/
|
2003-12-03 09:44:28 +01:00
|
|
|
const bool leafPage = (page->btr_level == 0);
|
|
|
|
const SCHAR flags = page->btr_header.pag_flags;
|
2003-12-01 11:25:41 +01:00
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
IndexNode node, previousNode;
|
2003-12-01 11:25:41 +01:00
|
|
|
pointer = readNode(&node, pointer, flags, leafPage);
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
// loop through duplicates until
|
|
|
|
// correct node is found.
|
|
|
|
// If this is an end bucket marker then return
|
|
|
|
// the previous passed page number.
|
|
|
|
if (BTreeNode::isEndBucket(&node, leafPage)) {
|
|
|
|
return previousNumber;
|
|
|
|
}
|
|
|
|
if (findRecordNumber < node.recordNumber) {
|
|
|
|
// If first record number on page is higher
|
|
|
|
// then record number must be at the previous
|
|
|
|
// passed page number.
|
|
|
|
return previousNumber;
|
|
|
|
}
|
|
|
|
else if (findRecordNumber == node.recordNumber) {
|
|
|
|
// If first record number on page is equal
|
|
|
|
// then we are exactly on the right place :)
|
|
|
|
return node.pageNumber;
|
|
|
|
}
|
|
|
|
// Save current page number and fetch next node
|
|
|
|
// for comparision.
|
|
|
|
previousNumber = node.pageNumber;
|
|
|
|
previousNode = node;
|
|
|
|
pointer = BTreeNode::readNode(&node, pointer, flags, leafPage);
|
|
|
|
// We're done if end level marker is reached or this
|
|
|
|
// isn't a equal node anymore.
|
|
|
|
if (BTreeNode::isEndLevel(&node, leafPage) ||
|
|
|
|
(node.length != 0) ||
|
|
|
|
(node.prefix != (previousNode.length + previousNode.prefix)))
|
|
|
|
{
|
|
|
|
return previousNumber;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We never reach this point
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
USHORT getJumpNodeSize(const IndexJumpNode* jumpNode, SCHAR flags)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t J u m p N o d e S i z e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Return the size needed to store
|
|
|
|
* this node.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT result = 0;
|
|
|
|
if (flags & btr_large_keys) {
|
|
|
|
// Size needed for prefix
|
2004-02-25 23:14:19 +01:00
|
|
|
USHORT number = jumpNode->prefix;
|
|
|
|
result++;
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
result++;
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
// Size needed for length
|
2004-02-25 23:14:19 +01:00
|
|
|
number = jumpNode->length;
|
|
|
|
result++;
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
result++;
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Size needed for prefix
|
|
|
|
result++;
|
|
|
|
// Size needed for length
|
|
|
|
result++;
|
|
|
|
}
|
|
|
|
// Size needed for offset
|
2004-02-25 23:14:19 +01:00
|
|
|
// NOTE! offset can be unknown when this function is called,
|
|
|
|
// therefor we can't use a compression method.
|
2003-12-01 11:25:41 +01:00
|
|
|
result += sizeof(USHORT);
|
|
|
|
// Size needed for data
|
|
|
|
result += jumpNode->length;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
USHORT getNodeSize(const IndexNode* indexNode, SCHAR flags, bool leafNode)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t N o d e S i z e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Return the size needed to store
|
|
|
|
* this node.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
USHORT result = 0;
|
|
|
|
if (flags & btr_large_keys) {
|
2004-02-25 23:14:19 +01:00
|
|
|
|
|
|
|
// Determine flags
|
|
|
|
SLONG number = indexNode->recordNumber;
|
|
|
|
if (!leafNode) {
|
|
|
|
number = indexNode->pageNumber;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
UCHAR internalFlags = 0;
|
|
|
|
if (number == END_BUCKET) {
|
|
|
|
internalFlags = 2;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
if (number == END_LEVEL) {
|
|
|
|
internalFlags = 1;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
if ((internalFlags == 0) &&
|
|
|
|
(indexNode->length == 0) && (indexNode->prefix == 0))
|
|
|
|
{
|
|
|
|
internalFlags = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store internal flags + 6 bits from number
|
|
|
|
if (!leafNode) {
|
|
|
|
number = indexNode->recordNumber;
|
|
|
|
}
|
|
|
|
if (number < 0) {
|
|
|
|
number = 0;
|
|
|
|
}
|
|
|
|
result++;
|
|
|
|
number >>= 6;
|
|
|
|
|
|
|
|
// Get size for storing remaining bits for number
|
2004-02-26 01:07:37 +01:00
|
|
|
if (number & 0xF0000000) {
|
|
|
|
result += 5;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2004-02-26 01:07:37 +01:00
|
|
|
else if (number & 0xFFE00000) {
|
|
|
|
result += 4;
|
|
|
|
}
|
|
|
|
else if (number & 0xFFFFC000) {
|
|
|
|
result += 3;
|
|
|
|
}
|
|
|
|
else if (number & 0xFFFFFF80) {
|
|
|
|
result += 2;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2004-02-26 01:07:37 +01:00
|
|
|
else {
|
|
|
|
result += 1;
|
|
|
|
}
|
|
|
|
|
2004-02-25 23:14:19 +01:00
|
|
|
|
|
|
|
if (!leafNode) {
|
|
|
|
// Size needed for page number
|
|
|
|
number = indexNode->pageNumber;
|
|
|
|
if (number < 0) {
|
2004-02-26 01:07:37 +01:00
|
|
|
number = 0;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
|
|
|
|
2004-02-26 01:07:37 +01:00
|
|
|
if (number & 0xF0000000) {
|
|
|
|
result += 5;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
2004-02-26 01:07:37 +01:00
|
|
|
else if (number & 0xFFE00000) {
|
|
|
|
result += 4;
|
|
|
|
}
|
|
|
|
else if (number & 0xFFFFC000) {
|
|
|
|
result += 3;
|
|
|
|
}
|
|
|
|
else if (number & 0xFFFFFF80) {
|
|
|
|
result += 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result += 1;
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (internalFlags != 3) {
|
|
|
|
// Size needed for prefix
|
|
|
|
number = indexNode->prefix;
|
2004-02-26 01:07:37 +01:00
|
|
|
UCHAR tmp = (number & 0x7F);
|
2004-02-25 23:14:19 +01:00
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
result++; // 7
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
result++; // 14
|
|
|
|
}
|
|
|
|
|
|
|
|
// Size needed for length
|
|
|
|
number = indexNode->length;
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
result++; // 7
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
result++; // 14
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
|
|
|
result += indexNode->length;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Size needed for prefix
|
|
|
|
result++;
|
|
|
|
// Size needed for length
|
|
|
|
result++;
|
|
|
|
// Size needed for page number
|
|
|
|
result += sizeof(SLONG);
|
|
|
|
|
2004-02-25 23:14:19 +01:00
|
|
|
result += indexNode->length;
|
2003-12-01 11:25:41 +01:00
|
|
|
|
2004-02-25 23:14:19 +01:00
|
|
|
if (!leafNode && (flags & btr_all_record_number)) {
|
|
|
|
// Size needed for record number
|
|
|
|
result += sizeof(SLONG);
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2003-12-01 11:25:41 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
UCHAR* getPointerFirstNode(btree_page* page, IndexJumpInfo* jumpInfo)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t P o i n t e r F i r s t N o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Return the pointer to first data node
|
|
|
|
* in the bucket. When a jumpInfo is
|
|
|
|
* given, then pointer of first jump
|
|
|
|
* node is returned.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (page->btr_header.pag_flags & btr_jump_info) {
|
|
|
|
if (jumpInfo) {
|
2003-12-03 09:44:28 +01:00
|
|
|
UCHAR* pointer = reinterpret_cast<UCHAR*>(page->btr_nodes);
|
2003-12-01 11:25:41 +01:00
|
|
|
return readJumpInfo(jumpInfo, pointer);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
IndexJumpInfo jumpInformation;
|
2003-12-03 09:44:28 +01:00
|
|
|
UCHAR* pointer = reinterpret_cast<UCHAR*>(page->btr_nodes);
|
2003-12-01 11:25:41 +01:00
|
|
|
readJumpInfo(&jumpInformation, pointer);
|
2003-12-03 09:44:28 +01:00
|
|
|
return reinterpret_cast<UCHAR*>(page) + jumpInformation.firstNodeOffset;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2003-12-03 09:44:28 +01:00
|
|
|
return reinterpret_cast<UCHAR*>(page->btr_nodes);
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
bool isEndBucket(const IndexNode* indexNode, bool leafNode)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i s E n d B u c k e t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check if this is a END_BUCKET
|
|
|
|
* marker node.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (leafNode) {
|
|
|
|
return (indexNode->recordNumber == END_BUCKET);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return (indexNode->pageNumber == END_BUCKET);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
bool isEndLevel(const IndexNode* indexNode, bool leafNode)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* i s E n d L e v e l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check if this is a END_LEVEL
|
|
|
|
* marker node.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (leafNode) {
|
|
|
|
return (indexNode->recordNumber == END_LEVEL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return (indexNode->pageNumber == END_LEVEL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
bool keyEquality(USHORT length, const UCHAR* data, const IndexNode* indexNode)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* k e y E q u a l i t y
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check a B-tree node against a key for equality.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
if (length != indexNode->length + indexNode->prefix) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
USHORT l = indexNode->length;
|
|
|
|
if (!l) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-12-03 09:44:28 +01:00
|
|
|
const UCHAR* p = indexNode->data;
|
|
|
|
const UCHAR* q = data + indexNode->prefix;
|
2003-12-01 11:25:41 +01:00
|
|
|
while (l) {
|
|
|
|
if (*p++ != *q++) {
|
|
|
|
return false;
|
|
|
|
}
|
2003-12-03 09:44:28 +01:00
|
|
|
--l;
|
2003-12-01 11:25:41 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SCROLLABLE_CURSORS
|
2004-02-20 07:43:27 +01:00
|
|
|
UCHAR* lastNode(btree_page* page, jrd_exp* expanded_page, BTX* expanded_node)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* 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 BTX, since there is always an extra
|
|
|
|
// BTX node with zero-length tail at the end of the page
|
|
|
|
BTX enode = (BTX) ((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);
|
2003-12-03 09:44:28 +01:00
|
|
|
const SCHAR flags = page->btr_header.pag_flags;
|
2003-12-01 11:25:41 +01:00
|
|
|
IndexNode node;
|
|
|
|
while (true) {
|
|
|
|
pointer = previousNode(&node, pointer, flags, &enode);
|
|
|
|
if (!isEndBucket(&node, false) &&
|
|
|
|
!isEndLevel(&node, false))
|
|
|
|
{
|
|
|
|
if (expanded_node) {
|
|
|
|
*expanded_node = enode;
|
|
|
|
}
|
|
|
|
return node.nodePointer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
UCHAR* nextNode(IndexNode* node, UCHAR* pointer,
|
|
|
|
SCHAR flags, BTX* expanded_node)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* n e x t N o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Find the next node on both the index page
|
|
|
|
* and its associated expanded buffer.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
pointer = readNode(node, pointer, flags, true);
|
|
|
|
|
|
|
|
if (*expanded_node) {
|
|
|
|
*expanded_node = (BTX) ((UCHAR*) (*expanded_node)->btx_data +
|
|
|
|
node->prefix + node->length);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UCHAR* previousNode(IndexNode* node, UCHAR* pointer,
|
|
|
|
SCHAR flags, BTX* 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 = (BTX) ((UCHAR*) *expanded_node - (*expanded_node)->btx_previous_length);
|
|
|
|
|
|
|
|
return pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void quad_put(SLONG value, UCHAR* data)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* q u a d _ p u t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Move SLONG to a four byte vector.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
|
|
|
|
const UCHAR* p = (UCHAR*) &value;
|
|
|
|
|
|
|
|
data[0] = p[0];
|
|
|
|
data[1] = p[1];
|
|
|
|
data[2] = p[2];
|
|
|
|
data[3] = p[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UCHAR* readJumpInfo(IndexJumpInfo* jumpInfo, UCHAR* pagePointer)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e a d J u m p I n f o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Read jump information from the page
|
|
|
|
* by the given pagePointer and the
|
|
|
|
* return the remaining position after
|
|
|
|
* the read.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
jumpInfo->firstNodeOffset = *reinterpret_cast<const USHORT*>(pagePointer);
|
|
|
|
pagePointer += sizeof(USHORT);
|
|
|
|
jumpInfo->jumpAreaSize = *reinterpret_cast<const USHORT*>(pagePointer);
|
|
|
|
pagePointer += sizeof(USHORT);
|
2003-12-03 09:44:28 +01:00
|
|
|
jumpInfo->jumpers = (USHORT)(*pagePointer);
|
|
|
|
++pagePointer;
|
2003-12-01 11:25:41 +01:00
|
|
|
return pagePointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UCHAR* readJumpNode(IndexJumpNode* jumpNode, UCHAR* pagePointer,
|
|
|
|
SCHAR flags)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e a d J u m p N o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Read a jump node from the page by the
|
|
|
|
* given pagePointer and the return the
|
|
|
|
* remaining position after the read.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
jumpNode->nodePointer = pagePointer;
|
|
|
|
if (flags & btr_large_keys) {
|
2004-02-25 23:14:19 +01:00
|
|
|
// Get prefix
|
|
|
|
UCHAR tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
jumpNode->prefix = (tmp & 0x7F);
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
jumpNode->prefix |= (tmp & 0x7F) << 7; // We get 14 bits at this point
|
|
|
|
}
|
|
|
|
// Get length
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
jumpNode->length = (tmp & 0x7F);
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
jumpNode->length |= (tmp & 0x7F) << 7; // We get 14 bits at this point
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
jumpNode->prefix = (USHORT)(UCHAR)(*pagePointer);
|
2004-02-25 23:14:19 +01:00
|
|
|
pagePointer++;
|
2003-12-01 11:25:41 +01:00
|
|
|
jumpNode->length = (USHORT)(UCHAR)(*pagePointer);
|
2004-02-25 23:14:19 +01:00
|
|
|
pagePointer++;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
jumpNode->offset = *reinterpret_cast<const USHORT*>(pagePointer);
|
|
|
|
pagePointer += sizeof(USHORT);
|
|
|
|
jumpNode->data = pagePointer;
|
|
|
|
pagePointer += jumpNode->length;
|
|
|
|
return pagePointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UCHAR* readNode(IndexNode* indexNode, UCHAR* pagePointer, SCHAR flags, bool leafNode)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* r e a d N o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Read a leaf/page node from the page by the
|
|
|
|
* given pagePointer and the return the
|
|
|
|
* remaining position after the read.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
indexNode->nodePointer = pagePointer;
|
|
|
|
if (flags & btr_large_keys) {
|
2004-02-25 23:14:19 +01:00
|
|
|
// Initialize
|
|
|
|
indexNode->prefix = 0;
|
|
|
|
indexNode->length = 0;
|
|
|
|
bool duplicate = false;
|
|
|
|
|
|
|
|
// Get first byte that contains internal flags and 6 bits from number
|
|
|
|
UCHAR internalFlags = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
SLONG number = (internalFlags & 0x3F);
|
|
|
|
internalFlags = ((internalFlags & 0xC0) >> 6);
|
2003-12-01 11:25:41 +01:00
|
|
|
pagePointer++;
|
2004-02-25 23:14:19 +01:00
|
|
|
|
|
|
|
if (internalFlags == BTN_DUPLICATE_FLAG) {
|
|
|
|
duplicate = true;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
|
|
|
// Get remaining bits for number
|
|
|
|
SLONG tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
2003-12-01 11:25:41 +01:00
|
|
|
pagePointer++;
|
2004-02-25 23:14:19 +01:00
|
|
|
number |= (tmp & 0x7F) << 6;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
2003-12-01 11:25:41 +01:00
|
|
|
pagePointer++;
|
2004-02-25 23:14:19 +01:00
|
|
|
number |= (tmp & 0x7F) << 13;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 20;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
2004-02-29 03:00:57 +01:00
|
|
|
number |= (tmp & 0x1F) << 27;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Change number to 64-bit type and enable this for 64-bit support
|
|
|
|
|
2004-02-25 23:14:19 +01:00
|
|
|
number |= (tmp & 0x7F) << 27;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 34;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 41;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 48;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 55; // We get 62 bits at this point!
|
|
|
|
}
|
|
|
|
}
|
2004-02-29 03:00:57 +01:00
|
|
|
}
|
|
|
|
}*/
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
2003-12-01 11:25:41 +01:00
|
|
|
if (leafNode) {
|
2004-02-25 23:14:19 +01:00
|
|
|
if ((internalFlags == BTN_END_LEVEL_FLAG) ||
|
|
|
|
(internalFlags == BTN_END_BUCKET_FLAG))
|
|
|
|
{
|
|
|
|
if (number == BTN_DUPLICATE_MARKER) {
|
|
|
|
duplicate = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (internalFlags == BTN_END_LEVEL_FLAG) {
|
|
|
|
number = END_LEVEL;
|
|
|
|
}
|
|
|
|
if (internalFlags == BTN_END_BUCKET_FLAG) {
|
|
|
|
number = END_BUCKET;
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
indexNode->recordNumber = number;
|
|
|
|
|
|
|
|
if (!leafNode) {
|
|
|
|
// Get page number for non-leaf pages
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number = (tmp & 0x7F);
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 7;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 14;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 21;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
2004-02-29 03:00:57 +01:00
|
|
|
number |= (tmp & 0x0F) << 28;
|
|
|
|
/*
|
|
|
|
Change number to 64-bit type and enable this for 64-bit support
|
|
|
|
|
2004-02-25 23:14:19 +01:00
|
|
|
number |= (tmp & 0x7F) << 28;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 35;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 42;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 49;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
number |= (tmp & 0x7F) << 56; // We get 63 bits at this point!
|
|
|
|
}
|
|
|
|
}
|
2004-02-29 03:00:57 +01:00
|
|
|
}
|
|
|
|
}*/
|
2004-02-25 23:14:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
indexNode->pageNumber = number;
|
|
|
|
|
|
|
|
if ((internalFlags == BTN_END_LEVEL_FLAG) ||
|
|
|
|
(internalFlags == BTN_END_BUCKET_FLAG))
|
|
|
|
{
|
|
|
|
if (number == BTN_DUPLICATE_MARKER) {
|
|
|
|
duplicate = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (internalFlags == BTN_END_LEVEL_FLAG) {
|
|
|
|
indexNode->pageNumber = END_LEVEL;
|
|
|
|
}
|
|
|
|
if (internalFlags == BTN_END_BUCKET_FLAG) {
|
|
|
|
indexNode->pageNumber = END_BUCKET;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get prefix and length if it isn't a duplicate
|
|
|
|
if (!duplicate) {
|
|
|
|
// Get prefix
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
indexNode->prefix = (tmp & 0x7F);
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
indexNode->prefix |= (tmp & 0x7F) << 7; // We get 14 bits at this point
|
|
|
|
}
|
|
|
|
// Get length
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
indexNode->length = (tmp & 0x7F);
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = *reinterpret_cast<const UCHAR*>(pagePointer);
|
|
|
|
pagePointer++;
|
|
|
|
indexNode->length |= (tmp & 0x7F) << 7; // We get 14 bits at this point
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get pointer where data starts
|
|
|
|
indexNode->data = pagePointer;
|
|
|
|
pagePointer += indexNode->length;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2003-12-03 09:44:28 +01:00
|
|
|
indexNode->prefix = (*pagePointer);
|
2003-12-01 11:25:41 +01:00
|
|
|
pagePointer++;
|
2003-12-03 09:44:28 +01:00
|
|
|
indexNode->length = (*pagePointer);
|
2003-12-01 11:25:41 +01:00
|
|
|
pagePointer++;
|
|
|
|
if (leafNode) {
|
|
|
|
indexNode->recordNumber = get_long(pagePointer);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
indexNode->pageNumber = get_long(pagePointer);
|
|
|
|
}
|
|
|
|
pagePointer += 4;
|
|
|
|
|
2004-02-25 23:14:19 +01:00
|
|
|
indexNode->data = pagePointer;
|
|
|
|
pagePointer += indexNode->length;
|
2003-12-01 11:25:41 +01:00
|
|
|
|
2004-02-25 23:14:19 +01:00
|
|
|
if (!leafNode && (flags & btr_all_record_number)) {
|
2003-12-01 11:25:41 +01:00
|
|
|
indexNode->recordNumber = get_long(pagePointer);
|
2004-02-25 23:14:19 +01:00
|
|
|
pagePointer += 4;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return pagePointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-02 12:02:12 +01:00
|
|
|
UCHAR* writeJumpInfo(btree_page* page, const IndexJumpInfo* jumpInfo)
|
2003-12-01 11:25:41 +01:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* w r i t e J u m p I n f o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Write jump information to the page by the
|
|
|
|
* given pointer.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
UCHAR* pointer = reinterpret_cast<UCHAR*> (page->btr_nodes);
|
|
|
|
*reinterpret_cast<USHORT*>(pointer) = jumpInfo->firstNodeOffset;
|
|
|
|
pointer += sizeof(USHORT);
|
|
|
|
*reinterpret_cast<USHORT*>(pointer) = jumpInfo->jumpAreaSize;
|
|
|
|
pointer += sizeof(USHORT);
|
|
|
|
*pointer = (UCHAR) jumpInfo->jumpers;
|
|
|
|
pointer++;
|
|
|
|
return pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UCHAR* writeJumpNode(IndexJumpNode* jumpNode, UCHAR* pagePointer,
|
|
|
|
SCHAR flags)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* w r i t e J u m p N o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Write jump information to the page by the
|
|
|
|
* given pointer.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
jumpNode->nodePointer = pagePointer;
|
|
|
|
if (flags & btr_large_keys) {
|
2004-02-25 23:14:19 +01:00
|
|
|
// Write prefix, maximum 14 bits
|
|
|
|
USHORT number = jumpNode->prefix;
|
|
|
|
UCHAR tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write length, maximum 14 bits
|
|
|
|
number = jumpNode->length;
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
*pagePointer = (UCHAR) jumpNode->prefix;
|
|
|
|
pagePointer++;
|
|
|
|
*pagePointer = (UCHAR) jumpNode->length;
|
|
|
|
pagePointer++;
|
|
|
|
}
|
|
|
|
*reinterpret_cast<USHORT*>(pagePointer) = jumpNode->offset;
|
|
|
|
pagePointer += sizeof(USHORT);
|
2004-02-25 23:14:19 +01:00
|
|
|
memmove(pagePointer, jumpNode->data, jumpNode->length);
|
|
|
|
pagePointer += jumpNode->length;
|
2003-12-01 11:25:41 +01:00
|
|
|
return pagePointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UCHAR* writeNode(IndexNode* indexNode, UCHAR* pagePointer, SCHAR flags,
|
|
|
|
bool leafNode, bool withData)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* w r i t e N o d e
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Write a leaf/page node to the page by the
|
|
|
|
* given page_pointer.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
indexNode->nodePointer = pagePointer;
|
|
|
|
if (flags & btr_large_keys) {
|
2004-02-25 23:14:19 +01:00
|
|
|
|
|
|
|
// AB: 2004-02-22
|
|
|
|
// To allow as much as compression possible we
|
|
|
|
// store numbers per 7 bit and the 8-th bit tell us
|
|
|
|
// if we need to go on reading or we're done.
|
|
|
|
// Also for duplicate node entries (length and prefix
|
|
|
|
// are zero) we don't store the length and prefix
|
|
|
|
// information. This will save at least 2 bytes per node.
|
|
|
|
|
|
|
|
bool duplicate = false;
|
|
|
|
SLONG number = indexNode->recordNumber;
|
|
|
|
if (!leafNode) {
|
|
|
|
number = indexNode->pageNumber;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
// Internal flags
|
|
|
|
UCHAR internalFlags = 0;
|
|
|
|
if (number == END_LEVEL) {
|
|
|
|
internalFlags = BTN_END_LEVEL_FLAG;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
else if (number == END_BUCKET) {
|
|
|
|
internalFlags = BTN_END_BUCKET_FLAG;
|
|
|
|
}
|
|
|
|
if (!leafNode) {
|
|
|
|
number = indexNode->recordNumber;
|
|
|
|
}
|
|
|
|
if ((indexNode->length == 0) && (indexNode->prefix == 0)) {
|
|
|
|
duplicate = true;
|
|
|
|
if (internalFlags == 0) {
|
|
|
|
// Duplicate value or ASC NULL state
|
|
|
|
internalFlags = BTN_DUPLICATE_FLAG;
|
|
|
|
}
|
|
|
|
else if (leafNode) {
|
|
|
|
// if we have a END_BUCKET or END_LEVEL marker we
|
|
|
|
// use the number for the duplicate information.
|
|
|
|
number = BTN_DUPLICATE_MARKER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (number < 0) {
|
|
|
|
number = 0;
|
|
|
|
}
|
|
|
|
// Store internal flags + 6 bits from number
|
|
|
|
UCHAR tmp = internalFlags;
|
|
|
|
*pagePointer = ((tmp << 6) | (number & 0x3F));
|
|
|
|
pagePointer++;
|
|
|
|
|
|
|
|
// Store remaining bits from number
|
|
|
|
number >>= 6;
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //13
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //20
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
2003-12-01 11:25:41 +01:00
|
|
|
pagePointer++;
|
2004-02-25 23:14:19 +01:00
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //27
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
2004-02-29 03:00:57 +01:00
|
|
|
tmp = (number & 0x1F);
|
|
|
|
number >>= 7; //34
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
/*
|
|
|
|
Change number to 64-bit type and enable this for 64-bit support
|
|
|
|
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //34
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //41
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //48
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //55
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
|
|
|
if (!leafNode) {
|
|
|
|
// Store page number for non-leaf pages
|
|
|
|
number = indexNode->pageNumber;
|
|
|
|
if (number < 0) {
|
|
|
|
if (duplicate) {
|
|
|
|
number = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
number = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
2003-12-01 11:25:41 +01:00
|
|
|
pagePointer++;
|
2004-02-25 23:14:19 +01:00
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //14
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //21
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //28
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
2004-02-29 03:00:57 +01:00
|
|
|
tmp = (number & 0x0F);
|
|
|
|
number >>= 7; //35
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
/*
|
|
|
|
Change number to 64-bit type and enable this for 64-bit support
|
2004-02-25 23:14:19 +01:00
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //35
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //42
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //49
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7; //56
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
|
|
|
// Store prefix and length when it isn't a duplicate
|
|
|
|
if (!duplicate) {
|
|
|
|
// Write prefix, maximum 14 bits
|
|
|
|
number = indexNode->prefix;
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write length, maximum 14 bits
|
|
|
|
number = indexNode->length;
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
number >>= 7;
|
|
|
|
if (number > 0) {
|
|
|
|
tmp |= 0x80;
|
|
|
|
}
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
if (tmp & 0x80) {
|
|
|
|
tmp = (number & 0x7F);
|
|
|
|
*pagePointer = tmp;
|
|
|
|
pagePointer++;
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
|
|
|
|
// Store data
|
|
|
|
if (withData) {
|
|
|
|
memcpy(pagePointer, indexNode->data, indexNode->length);
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
else {
|
2004-02-25 23:14:19 +01:00
|
|
|
memmove(pagePointer, indexNode->data, indexNode->length);
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
pagePointer += indexNode->length;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Write prefix
|
|
|
|
*pagePointer = (UCHAR)indexNode->prefix;
|
|
|
|
pagePointer++;
|
|
|
|
// Write length
|
|
|
|
*pagePointer = (UCHAR)indexNode->length;
|
|
|
|
pagePointer++;
|
|
|
|
if (leafNode) {
|
|
|
|
// Write record number
|
|
|
|
quad_put(indexNode->recordNumber, pagePointer);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Write page number
|
|
|
|
quad_put(indexNode->pageNumber, pagePointer);
|
|
|
|
}
|
2004-02-25 23:14:19 +01:00
|
|
|
pagePointer += sizeof(SLONG);
|
|
|
|
|
|
|
|
if (withData) {
|
|
|
|
USHORT size = indexNode->length;
|
|
|
|
const UCHAR* ptr = indexNode->data;
|
|
|
|
while (size) {
|
|
|
|
*pagePointer++ = *ptr++;
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
}
|
2003-12-01 11:25:41 +01:00
|
|
|
else {
|
2004-02-25 23:14:19 +01:00
|
|
|
pagePointer += indexNode->length;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!leafNode && (flags & btr_all_record_number)) {
|
|
|
|
// Write record number
|
|
|
|
if (flags & btr_large_keys) {
|
|
|
|
*reinterpret_cast<SLONG*>(pagePointer) = indexNode->recordNumber;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
quad_put(indexNode->recordNumber, pagePointer);
|
|
|
|
}
|
|
|
|
pagePointer += sizeof(SLONG);
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pagePointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void setEndBucket(IndexNode* indexNode, bool leafNode)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e t E n d B u c k e t
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
if (leafNode) {
|
|
|
|
indexNode->recordNumber = END_BUCKET;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
indexNode->pageNumber = END_BUCKET;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void setEndLevel(IndexNode* indexNode, bool leafNode)
|
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s e t E n d L e v e l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
indexNode->prefix = 0;
|
|
|
|
indexNode->length = 0;
|
|
|
|
if (leafNode) {
|
|
|
|
indexNode->recordNumber = END_LEVEL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
indexNode->pageNumber = END_LEVEL;
|
2004-02-25 23:14:19 +01:00
|
|
|
indexNode->recordNumber = 0;
|
2003-12-01 11:25:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace BTreeNode
|