/*
* Copyright (C) 2002 by the Massachusetts Institute of Technology.
* All rights reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*/
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#endif /* LIBC_SCCS and not lint */
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "db-int.h"
#include "btree.h"
/*
* Sequential scan support.
*
* The tree can be scanned sequentially, starting from either end of the
* tree or from any specific key. A scan request before any scanning is
* done is initialized as starting from the least node.
*/
/*
* __bt_seq --
* Btree sequential scan interface.
*
* Parameters:
* dbp: pointer to access method
* key: key for positioning and return value
* data: data return value
* flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
int
{
BTREE *t;
EPG e;
int status;
/* Toss any page pinned across calls. */
}
/*
* If scan unitialized as yet, or starting at a specific record, set
* the scan to a specific key. Both __bt_seqset and __bt_seqadv pin
* the page the cursor references if they're successful.
*/
switch (flags) {
case R_NEXT:
case R_PREV:
break;
}
/* FALLTHROUGH */
case R_FIRST:
case R_LAST:
case R_CURSOR:
break;
default:
return (RET_ERROR);
}
if (status == RET_SUCCESS) {
status =
/*
* If the user is doing concurrent access, we copied the
*/
else
}
return (status);
}
/*
* __bt_seqset --
* Set the sequential scan to a specific key.
*
* Parameters:
* t: tree
* ep: storage for returned key
* key: key for initial scan position
* flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
*
* Side effects:
* Pins the page the cursor references.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
BTREE *t;
int flags;
{
PAGE *h;
int exact;
/*
* Find the first, last or specific key in the tree and point the
* cursor at it. The cursor may not be moved until a new key has
* been found.
*/
switch (flags) {
case R_CURSOR: /* Keyed scan. */
/*
* Find the first instance of the key or the smallest key
* which is greater than or equal to the specified key.
*/
return (RET_ERROR);
}
case R_FIRST: /* First record. */
case R_NEXT:
/* Walk down the left-hand side of the tree. */
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
return (RET_SPECIAL);
}
break;
}
break;
case R_LAST: /* Last record. */
case R_PREV:
/* Walk down the right-hand side of the tree. */
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
return (RET_SPECIAL);
}
break;
}
break;
}
return (RET_SUCCESS);
}
/*
* __bt_seqadvance --
* Advance the sequential scan.
*
* Parameters:
* t: tree
* flags: R_NEXT, R_PREV
*
* Side effects:
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
BTREE *t;
int flags;
{
CURSOR *c;
PAGE *h;
/*
* There are a couple of states that we can be in. The cursor has
* been initialized by the time we get here, but that's all we know.
*/
c = &t->bt_cursor;
/*
* The cursor was deleted and there weren't any duplicate records,
* so the cursor's key was saved. Find out where that key would
* be in the current tree. If the returned key is an exact match,
* the delete. We could reasonably return the key, but the problem
* is that this is the access pattern we'll see if the user is
* doing seq(..., R_NEXT)/put(..., 0) pairs, i.e. the put deletes
* the cursor record and then replaces it, so the cursor was saved,
* and we'll simply return the same "new" record until the user
* notices and doesn't do a put() of it. Since the key is an exact
* match, we could as easily put the new record before the cursor,
* and we've made no guarantee to return it. So, move forward or
* back a record if it's an exact match.
*
* XXX
* In the current implementation, put's to the cursor are done with
* that seq(..., R_NEXT)/put(..., R_CURSOR) pairs are going to exhibit
* the same behavior as above. Second, you can return the same key
* twice if you have duplicate records. The scenario is that the
* cursor record is deleted, moving the cursor forward or backward
* to a duplicate. The add then inserts the new record at a location
* ahead of the cursor because duplicates aren't sorted in any way,
* and the new record is later returned. This has to be fixed at some
* point.
*/
if (F_ISSET(c, CURS_ACQUIRE)) {
return (RET_ERROR);
if (!exact)
return (rval);
/*
* XXX
* Kluge -- get, release, get the page.
*/
}
/* Get the page referenced by the cursor. */
return (RET_ERROR);
/*
* it. The cursor may not be moved until a new key has been found.
*/
switch (flags) {
case R_NEXT: /* Next record. */
/*
* The cursor was deleted in duplicate records, and moved
* forward to a record that has yet to be returned. Clear
* that flag, and return the record.
*/
if (F_ISSET(c, CURS_AFTER))
goto usecurrent;
return (RET_SPECIAL);
return (RET_ERROR);
idx = 0;
}
break;
case R_PREV: /* Previous record. */
/*
* The cursor was deleted in duplicate records, and moved
* backward to a record that has yet to be returned. Clear
* that flag, and return the record.
*/
if (F_ISSET(c, CURS_BEFORE)) {
return (RET_SUCCESS);
}
if (idx == 0) {
return (RET_SPECIAL);
return (RET_ERROR);
} else
--idx;
break;
}
return (RET_SUCCESS);
}
/*
* __bt_first --
* Find the first entry.
*
* Parameters:
* t: the tree
* key: the key
* erval: return EPG
* exactp: pointer to exact match flag
*
* Returns:
* The first entry in the tree greater than or equal to key,
* or RET_SPECIAL if no such key exists.
*/
static int
BTREE *t;
int *exactp;
{
/*
* Find any matching record; __bt_search pins the page.
*
* If it's an exact match and duplicates are possible, walk backwards
* in the tree until we find the first one. Otherwise, make sure it's
* a valid key (__bt_search may return an index just past the end of a
* page) and return it.
*/
return (RET_SPECIAL);
if (*exactp) {
return (RET_SUCCESS);
}
/*
* Walk backwards, as long as the entry matches and there are
* keys left in the tree. Save a copy of each match in case
* we go too far.
*/
do {
} else
/*
* Don't unpin the page the last (or original) match
* was on, but make sure it's unpinned if an error
* occurs.
*/
break;
/*
* Solaris Kerberos
*/
return (RET_ERROR);
}
}
/*
* Reach here with the last page that was looked at pinned,
* which may or may not be the same as the last (or original)
* match page. If it's not useful, release it.
*/
return (RET_SUCCESS);
}
/* If at the end of a page, find the next entry. */
return (RET_SPECIAL);
return (RET_ERROR);
}
return (RET_SUCCESS);
}
/*
* __bt_setcur --
* Set the cursor to an entry in the tree.
*
* Parameters:
* t: the tree
* pgno: page number
* index: page index
*/
void
BTREE *t;
{
/* Lose any already deleted key. */
}
/* Update the cursor. */
}
/* Recursive descent cursor. */
typedef struct rcursor_ {
} RCURSOR;
static int bt_rcinit(void **);
static void bt_rcdestroy(void **);
static int bt_rcgrowstk(RCURSOR *);
static int
void **curs;
{
return RET_ERROR;
}
return RET_ERROR;
}
return RET_SUCCESS;
}
static void
void **curs;
{
}
static int
db_pgno_t p;
u_int i;
{
int status;
if (status != RET_SUCCESS)
return status;
}
return RET_SUCCESS;
}
static EPGNO *
{
}
static void
{
}
static int
{
EPGNO *e;
if (e == NULL) {
return RET_ERROR;
}
return RET_SUCCESS;
}
/*
* bt_rseq --
* Like __bt_seq but does recursive descent tree traversal
*/
int
void **curs;
{
BTREE *t;
EPG e;
int status;
/* Toss any page pinned across calls. */
}
return RET_ERROR;
}
if (status != RET_SUCCESS)
return RET_ERROR;
}
/*
* If scan unitialized as yet, or starting at a specific record, set
* the scan to a specific key. Both bt_rseqset and bt_rseqadv pin
* the page the cursor references if they're successful.
*/
switch (flags) {
case R_NEXT:
case R_PREV:
break;
}
/* FALLTHROUGH */
case R_FIRST:
case R_LAST:
case R_CURSOR:
break;
default:
return (RET_ERROR);
}
if (status == RET_SUCCESS) {
status =
/*
* If the user is doing concurrent access, we copied the
*/
else
} else if (status == RET_SPECIAL)
return (status);
}
/*
* bt_rseqset --
* Set the sequential scan to a specific key.
*
* Parameters:
* t: tree
* ep: storage for returned key
* key: key for initial scan position
* rc: recursion cursor
* flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
*
* Side effects:
* Pins the page the cursor references.
* Updates rc's stack and cursor.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
BTREE *t;
int flags;
{
PAGE *h;
int status;
/*
* Find the first, last or specific key in the tree and point the
* cursor at it. The cursor may not be moved until a new key has
* been found.
*/
switch (flags) {
case R_CURSOR: /* Not implemented. */
return RET_ERROR;
case R_FIRST: /* First record. */
case R_NEXT:
/* Walk down the left-hand side of the tree. */
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
return (RET_SPECIAL);
}
break;
if (status != RET_SUCCESS)
return status;
}
break;
case R_LAST: /* Last record. */
case R_PREV:
/* Walk down the right-hand side of the tree. */
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
return (RET_SPECIAL);
}
break;
if (status != RET_SUCCESS)
return status;
}
break;
}
return (RET_SUCCESS);
}
/*
* bt_rseqadvance --
* Advance the sequential scan.
*
* Parameters:
* t: tree
* ep: return page
* rc: recursion cursor
* flags: R_NEXT, R_PREV
*
* Side effects:
* Updates rc's stack and cursor.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
BTREE *t;
int flags;
{
CURSOR *c;
PAGE *h;
int status;
EPGNO *e;
/*
* There are a couple of states that we can be in. The cursor has
* been initialized by the time we get here, but that's all we know.
*/
/* Get the page referenced by the cursor. */
return (RET_ERROR);
/*
* it. The cursor may not be moved until a new key has been found.
*/
switch (flags) {
case R_NEXT: /* Next record. */
/* Crawl up if we hit the right edge. */
if (e == NULL) /* Hit the right edge of root. */
return RET_SPECIAL;
return (RET_ERROR);
}
/* Crawl down the left until we hit a leaf. */
if (status != RET_SUCCESS)
return status;
return (RET_ERROR);
idx = 0;
}
break;
case R_PREV: /* Previous record. */
while (!idx) {
/* Crawl up if we hit the left edge. */
if (e == NULL) /* Hit the left edge of root. */
return RET_SPECIAL;
return (RET_ERROR);
}
idx--;
/* Crawl down the right until we hit a leaf. */
if (status != RET_SUCCESS)
return status;
return (RET_ERROR);
}
break;
}
return (RET_SUCCESS);
}