2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: keyfcns.c /main/3 1996/08/12 12:34:31 cde-ibm $ */
25 * COMPONENT_NAME: austext
27 * FUNCTIONS: NODE_WIDTH
53 * OBJECT CODE ONLY SOURCE MATERIALS
55 /*---------------------------------------------------------------------------
56 db_VISTA Key File/Field Manipulation Functions
57 ----------------------------------------------
58 An implementation of the B-tree indexing method described in
59 "Sorting and Searching: The Art of Computer Programming, Vol III",
60 Knuth, Donald E., Addison-Wesley, 1975. pp 473-480.
62 A more detailed description of the generic algorithms can be found
63 in "Fundamentals of Data Structures in Pascal", Horowitz & Sahni,
64 Computer Science Press, 1984. pp 491-512.
66 A tutorial survey of B-tree methods can be found in "The Ubiquitous
67 B-Tree", Comer, D., ACM Computing Surveys, Vol 11, No. 2, June 1979.
69 (C) Copyright 1985, 1986, 1987 by Raima Corp.
71 ---------------------------------------------------------------------------*/
73 /* ********************** EDIT HISTORY *******************************
75 SCR DATE INI DESCRIPTION
76 ----- --------- --- -----------------------------------------------------
77 158 15-JUN-88 RSC added compliment flag to key_bldcom
78 42 15-JUN-88 RSC make keynext 4X faster!!
79 04-Aug-88 RTK MULTI_TASK changes
80 310 10-Aug-88 RSC cleanup function prototypes
81 420 16-Sep-88 RTK Several missing FAR pointers
82 420 16-Sep-88 RTK np_ptr not initialized in d_prkeys
83 536 06-Jan-89 RSC pointer can go negative in node_search if 1st slot matches
84 21-Feb-89 RSC add consistency check to key_locpos
85 16-Mar-89 WLW reset table pointers in d_keyread
92 /* Data definitions used for the B-tree algorithms */
94 /* node number of root */
97 /* null node pointer */
100 /* index file node structure */
102 LONG last_chgd; /* date/time of last change of this node */
103 INT used_slots; /* current # of used slots in node */
104 char slots[1]; /* start of slot area */
106 /* Number of used slots plus orphan */
107 #define NODE_WIDTH(node) ((node)->used_slots*slot_len + sizeof(F_ADDR))
109 /* last status value */
113 #define KEYNOTFOUND 2
116 /* Internal function prototypes */
117 static int node_search(P1(CONST char FAR *) Pi(DB_ADDR FAR *)
118 Pi(NODE FAR *) Pi(int *) Pi(int *)
120 static int keycmp(P1(CONST char FAR *) Pi(KEY_SLOT FAR *)
122 static int expand(P1(CONST char FAR *) Pi(DB_ADDR) Pi(F_ADDR));
123 static int split_root(P1(NODE FAR *));
124 static int split_node(P1(F_ADDR) Pi(NODE FAR *));
125 static int delete(P0);
126 static void open_slots(P1(NODE FAR *) Pi(int) Pi(int));
127 static void close_slots(P1(NODE FAR *) Pi(int) Pi(int));
128 static void key_found(P1(DB_ADDR *));
134 static KEY_INFO FAR *curkey;
138 static int max_slots;
142 static FIELD_ENTRY FAR *cfld_ptr;
150 /* Open B-tree key field index processing
155 int fd_lc; /* loop control */
156 long t; /* total keys thru level l */
157 int l; /* level number */
158 int i; /* field subscript */
159 FIELD_ENTRY FAR *fld_ptr;
160 KEY_INFO FAR *ki_ptr;
161 FILE_ENTRY FAR *file_ptr;
163 /* child ptr key number */
164 key_data = sizeof(F_ADDR) + sizeof(INT);
166 /* count total number of key fields */
168 for (fd_lc = size_fd - old_size_fd, fld_ptr = &field_table[old_size_fd];
169 --fd_lc >= 0; ++fld_ptr) {
170 if (fld_ptr->fd_key != NOKEY )
175 /* Macro references must be on one line for some compilers */
177 ALLOC(&db_global.Key_info, no_of_keys*sizeof(KEY_INFO), "key_info");
179 return( dberr(S_NOMEMORY) );
180 for (i = 0, fld_ptr = &field_table[old_size_fd];
181 i < size_fd; ++i, ++fld_ptr) {
182 if ( fld_ptr->fd_key != NOKEY ) {
183 ki_ptr = &key_info[fld_ptr->fd_keyno];
185 ki_ptr->lstat = KEYINIT;
187 ki_ptr->keyfile = fld_ptr->fd_keyfile;
188 ki_ptr->dba = NULL_DBA;
189 file_ptr = &file_table[fld_ptr->fd_keyfile];
191 /* Macro references must be on one line for some compilers */
192 ALLOC(&ki_ptr->Keyval, file_ptr->ft_slsize, db_avname);
193 if ( ! ki_ptr->keyval )
194 return( dberr(S_NOMEMORY) );
195 MEM_UNLOCK(&ki_ptr->Keyval);
196 /* compute maximum possible levels */
197 for (t = file_ptr->ft_slots, l = 1; t < MAXRECORDS; ++l)
198 t *= file_ptr->ft_slots;
199 ki_ptr->max_lvls = ++l;
202 ALLOC(&ki_ptr->Node_path, l*sizeof(NODE_PATH), db_avname);
203 if ( ! ki_ptr->node_path )
204 return( dberr(S_NOMEMORY) );
205 byteset(ki_ptr->node_path, 0, l*sizeof(NODE_PATH));
206 MEM_UNLOCK(&ki_ptr->Node_path);
210 return( db_status = S_OKAY );
215 /* Close key field processing
220 KEY_INFO FAR *ki_ptr;
223 /* free memory allocated for key functions */
224 for (k = 0, ki_ptr = key_info; k < no_of_keys; ++k, ++ki_ptr) {
225 MEM_UNLOCK(&ki_ptr->Node_path);
226 FREE(&ki_ptr->Node_path);
227 MEM_UNLOCK(&ki_ptr->Keyval);
228 FREE(&ki_ptr->Keyval);
230 MEM_UNLOCK(&db_global.Key_info);
231 FREE(&db_global.Key_info);
236 /* Initialize key function operation
240 int field; /* field number to be processed */
242 FIELD_ENTRY FAR *fld_ptr;
243 FILE_ENTRY FAR *file_ptr;
245 fld_ptr = &field_table[field];
246 if ( fld_ptr->fd_key == NOKEY )
247 return( dberr(S_NOTKEY) );
251 keyno = fld_ptr->fd_keyno;
253 prefix = keyno - curr_db_table->key_offset;
255 key_len = fld_ptr->fd_len;
256 keyfile = fld_ptr->fd_keyfile;
257 file_ptr = &file_table[keyfile];
258 slot_len = file_ptr->ft_slsize;
259 max_slots = file_ptr->ft_slots;
260 mid_slot = max_slots/2;
261 curkey = &key_info[keyno];
262 unique = (fld_ptr->fd_key == UNIQUE);
263 dio_setdef( keyfile );
265 return( db_status = S_OKAY );
270 /* Reset key_info last status to reposition keys on file "fno"
277 KEY_INFO FAR *ki_ptr;
279 for (i = 0, ki_ptr = key_info; i < no_of_keys; ++i, ++ki_ptr) {
280 if (((fno == size_ft) || (ki_ptr->keyfile == fno)) &&
281 ((ki_ptr->lstat == KEYFOUND) || (ki_ptr->lstat == KEYNOTFOUND)))
282 ki_ptr->lstat = KEYREPOS;
284 return( db_status = S_OKAY );
289 /* Locate proper key position on B-tree
292 key_locpos(key_val, dba)
293 CONST char FAR *key_val; /* key search value */
294 DB_ADDR FAR *dba; /* database address of located key */
296 NODE FAR *node; /* pointer to current node */
297 F_ADDR child; /* page number of child node */
298 F_ADDR pg; /* page number of current node */
299 int stat; /* saves node search status */
301 int match_lvl; /* lowest level with duplicate key */
302 NODE_PATH FAR *np_ptr;
303 char FAR *node_slot_ptr;
306 MEM_LOCK(&curkey->Node_path);
307 for (curkey->level = 0, np_ptr = curkey->node_path, pg = ROOT_ADDR;
309 ++curkey->level, ++np_ptr, pg = child) {
310 /* read in next node */
311 if ( dio_get(pg, (char FAR * FAR *)&node, NOPGHOLD) != S_OKAY ) {
312 MEM_UNLOCK(&curkey->Node_path);
317 if ( curkey->level == 0 && node->used_slots == 0 ) {
319 curkey->lstat = KEYEOF;
320 MEM_UNLOCK(&curkey->Node_path);
321 return( db_status = S_NOTFOUND );
323 else if (node->used_slots == 0)
324 return( dberr( S_SYSERR ) ); /* non-root nodes can't be empty */
326 /* search node for key */
327 stat = node_search(key_val, ((*dba == NULL_DBA) ? NULL : dba), node,
328 &slot, &slot_pos, &child);
331 node_slot_ptr = &node->slots[slot_pos];
332 if ( stat == S_OKAY ) {
333 if ( unique || *dba != NULL_DBA )
336 /* mark level as having matching key */
337 match_lvl = curkey->level;
339 /* save the key value */
340 bytecpy(&key_type, node_slot_ptr, slot_len);
342 /* check for end of search */
343 if ( child == NULL_NODE )
346 if ( match_lvl >= 0 ) {
347 /* set to lowest duplicate key */
348 curkey->level = match_lvl;
350 curkey->lstat = KEYFOUND;
352 else if ( stat == S_OKAY ) {
353 bytecpy(&key_type, node_slot_ptr, slot_len);
355 curkey->lstat = KEYFOUND;
358 /* key not found - save key at positioned slot */
359 if ( np_ptr->slot > 0 )
360 node_slot_ptr -= slot_len;
361 bytecpy(&key_type, node_slot_ptr, slot_len);
362 curkey->lstat = KEYNOTFOUND;
363 db_status = S_NOTFOUND;
365 MEM_UNLOCK(&curkey->Node_path);
366 MEM_LOCK(&curkey->Keyval);
367 /* save key value and database address for possible repositioning */
368 bytecpy(curkey->keyval, key_type.ks.data, key_len);
369 MEM_UNLOCK(&curkey->Keyval);
370 bytecpy(&curkey->dba, &key_type.ks.data[key_len], sizeof(DB_ADDR));
372 /* return database address for d_keyfind */
373 if ( *dba == NULL_DBA )
374 bytecpy(dba, &curkey->dba, sizeof(DB_ADDR));
381 /* Search node for key value
383 static int node_search(key_val, dba, node, slotno, slot_offset,
385 CONST char FAR *key_val; /* key being searched */
386 DB_ADDR FAR *dba; /* database address included in comparison if not null */
387 NODE FAR *node; /* node being searched */
388 int *slotno; /* slot number of key position in node */
389 int *slot_offset; /* slot position offset */
390 F_ADDR *child; /* child ptr of located key */
392 int cmp, i, l, u, slot_pos;
393 char FAR *node_slot_ptr;
395 /* perform binary search on node */
397 u = node->used_slots - 1;
400 node_slot_ptr = &node->slots[slot_pos = i*slot_len];
401 if ( (cmp = keycmp(key_val, (KEY_SLOT FAR *)node_slot_ptr, dba)) < 0 )
405 else if ( i && !unique && !dba ) {
406 /* backup to lowest duplicate in node */
407 while (keycmp(key_val, (KEY_SLOT FAR *)(node_slot_ptr -= slot_len),
409 slot_pos -= slot_len;
410 if (--i == 0) goto have_slot;
412 node_slot_ptr += slot_len;
419 if ( cmp > 0 ) { /* always return next highest position */
421 node_slot_ptr += slot_len;
422 slot_pos += slot_len;
424 /* return child pointer from located slot */
425 bytecpy(child, node_slot_ptr, sizeof(F_ADDR));
427 /* return slot number */
429 *slot_offset = slot_pos;
431 return( db_status = (cmp == 0 ? S_OKAY : S_NOTFOUND) );
438 static int keycmp(key_val, slot, dba)
439 CONST char FAR *key_val; /* key value */
440 KEY_SLOT FAR *slot; /* pointer to key slot to be compared */
441 DB_ADDR FAR *dba; /* database address included in comparison if not null */
444 returns < 0 if key_val < slot
445 > 0 if key_val > slot
446 = 0 if key_val == slot
450 if (((cmp = INTcmp((char FAR *)&prefix, (char FAR *)&slot->keyno)) == 0) &&
451 ((cmp = fldcmp(cfld_ptr, key_val, slot->data)) == 0) &&
453 cmp = ADDRcmp(dba, (DB_ADDR FAR *)&slot->data[key_len]);
459 /* Scan thru key field
463 int fcn; /* next or prev */
464 DB_ADDR *dba; /* db address of scanned record */
468 NODE_PATH FAR *np_ptr;
469 char FAR *node_slot_ptr;
471 /* locate next key on file */
472 switch ( curkey->lstat ) {
475 return( key_boundary(((fcn == KEYNEXT) ? KEYFRST : KEYLAST), dba) );
477 MEM_LOCK(&curkey->Keyval);
478 key_locpos(curkey->keyval, &curkey->dba);
479 MEM_UNLOCK(&curkey->Keyval);
480 if (db_status != S_OKAY)
484 MEM_LOCK(&curkey->Node_path);
486 ++curkey->node_path[curkey->level].slot;
487 MEM_UNLOCK(&curkey->Node_path);
489 MEM_LOCK(&curkey->Node_path);
490 np_ptr = &curkey->node_path[curkey->level];
491 if (dio_get(np_ptr->node, (char FAR * FAR *)&node, NOPGHOLD) != S_OKAY) {
492 MEM_UNLOCK(&curkey->Node_path);
495 node_slot_ptr = &node->slots[np_ptr->slot*slot_len];
496 bytecpy(&child, node_slot_ptr, sizeof(F_ADDR));
497 if (child == NULL_NODE) {
498 if (fcn == KEYPREV) {
500 node_slot_ptr -= slot_len;
502 while (((fcn == KEYNEXT) && (np_ptr->slot >= node->used_slots)) ||
503 ((fcn == KEYPREV) && (np_ptr->slot < 0))) {
504 if (curkey->level <= 0) {
505 /* return end of file */
506 curkey->lstat = KEYEOF;
507 MEM_UNLOCK(&curkey->Node_path);
508 return( db_status = S_NOTFOUND );
511 node_slot_ptr = NULL;
512 if (dio_get((--np_ptr)->node, (char FAR * FAR *)&node,
513 NOPGHOLD) != S_OKAY) {
514 MEM_UNLOCK(&curkey->Node_path);
520 if (node_slot_ptr == NULL)
521 node_slot_ptr = &node->slots[np_ptr->slot*slot_len];
523 else do { /* move down to leaf node */
524 if ( dio_get(child, (char FAR * FAR *)&node, NOPGHOLD) != S_OKAY ) {
525 MEM_UNLOCK(&curkey->Node_path);
529 (++np_ptr)->node = child;
530 if (fcn == KEYNEXT) {
532 node_slot_ptr = node->slots;
535 np_ptr->slot = node->used_slots;
536 node_slot_ptr = &node->slots[np_ptr->slot*slot_len];
538 bytecpy(&child, node_slot_ptr, sizeof(F_ADDR));
539 } while ( child != NULL_NODE );
541 if (np_ptr->slot == node->used_slots) {
543 node_slot_ptr -= slot_len;
546 bytecpy(&key_type, node_slot_ptr, slot_len);
547 if (key_type.ks.keyno == prefix)
550 curkey->lstat = KEYEOF;
551 db_status = S_NOTFOUND;
553 MEM_UNLOCK(&curkey->Node_path);
558 /* Key has been found. Save appropriate information
560 static void key_found(dba)
563 MEM_LOCK(&curkey->Keyval);
564 /* save key value and database address for possible repositioning */
565 bytecpy(curkey->keyval, key_type.ks.data, key_len);
566 MEM_UNLOCK(&curkey->Keyval);
567 bytecpy(&curkey->dba, &key_type.ks.data[key_len], sizeof(DB_ADDR));
569 /* return found db addr */
572 curkey->lstat = KEYFOUND; /*[42] FOUND a match */
580 key_boundary(fcn, dba )
581 int fcn; /* KEYFRST or KEYLAST */
582 DB_ADDR *dba; /* to get dba of first or last key */
584 F_ADDR pg; /* node number */
585 NODE FAR *node; /* pointer to node contents in cache */
586 int cmp; /* keycmp result */
587 int match_lvl; /* lowest level containing matched key */
588 int lvl; /* node_path level variable */
589 int slot; /* slot position in node */
590 NODE_PATH FAR *np_ptr;
591 char FAR *node_slot_ptr;
593 if ( fcn == KEYFIND ) {
594 curkey->lstat = KEYINIT;
595 return( db_status = S_OKAY );
597 curkey->lstat = KEYNOTFOUND;
599 /* traverse B-tree for first or last key with specified prefix */
602 MEM_LOCK(&curkey->Node_path);
603 for (lvl = 0; TRUE; ++lvl) {
605 if ( dio_get(pg, (char FAR * FAR *)&node, NOPGHOLD) != S_OKAY ) {
606 MEM_UNLOCK(&curkey->Node_path);
609 if ( node->used_slots == 0 ) {
610 /* must not be anything on file */
611 curkey->lstat = KEYEOF;
612 MEM_UNLOCK(&curkey->Node_path);
613 return( db_status = S_NOTFOUND );
615 if ( fcn == KEYFRST ) {
616 for (slot = 0, node_slot_ptr = node->slots;
617 slot < node->used_slots;
618 ++slot, node_slot_ptr += slot_len) {
619 if ((cmp = INTcmp((char FAR *)&prefix,
620 (char FAR *)(node_slot_ptr + sizeof(F_ADDR)))) <= 0)
625 for (slot = node->used_slots - 1,
626 node_slot_ptr = &node->slots[slot*slot_len];
628 --slot, node_slot_ptr -= slot_len) {
629 if ((cmp = INTcmp((char FAR *)&prefix,
630 (char FAR *)(node_slot_ptr + sizeof(F_ADDR)))) >= 0)
634 /* save node path position */
635 np_ptr = &curkey->node_path[lvl];
640 /* save matched level & key value */
642 bytecpy(&key_type, node_slot_ptr, slot_len);
644 /* fetch appropriate child pointer */
646 node_slot_ptr += slot_len;
647 bytecpy(&pg, node_slot_ptr, sizeof(F_ADDR));
649 if ( pg == NULL_NODE ) break;
651 if ( match_lvl >= 0 ) {
652 curkey->level = match_lvl;
654 curkey->lstat = KEYREPOS; /*[42] Need to reposition */
657 /* no keys on file with requested prefix */
659 curkey->lstat = KEYEOF;
660 db_status = S_NOTFOUND;
662 MEM_UNLOCK(&curkey->Node_path);
667 /* Insert key field into B-tree
670 key_insert(fld, key_val, dba )
671 int fld; /* key field number */
672 CONST char FAR *key_val; /* key value */
673 DB_ADDR dba; /* record's database address */
677 /* initialize key function operation */
678 if ( key_init(fld) != S_OKAY ) return( db_status );
680 /* locate insertion point */
681 if ( key_locpos(key_val, &dba) == S_NOTFOUND ) {
682 /* expand node to include key */
683 if ( (stat = expand(key_val, dba, NULL_NODE)) == S_OKAY ) {
684 /* save key value and database address for possible repositioning */
685 MEM_LOCK(&curkey->Keyval);
686 bytecpy(curkey->keyval, key_val, key_len);
687 MEM_UNLOCK(&curkey->Keyval);
690 /* reset key position */
691 key_reset(curkey->keyfile);
695 else if ( db_status == S_OKAY )
703 /* Expand node for new key
705 static int expand(key_val, dba, brother )
706 CONST char FAR *key_val; /* key value */
707 DB_ADDR dba; /* record's database address */
708 F_ADDR brother; /* page number of brother node */
712 NODE_PATH FAR *np_ptr;
714 char FAR *node_slot_ptr;
716 MEM_LOCK(&curkey->Node_path);
717 np_ptr = &curkey->node_path[curkey->level];
719 if (dio_get(pg = np_ptr->node, (char FAR * FAR *)&node, PGHOLD) != S_OKAY) {
720 MEM_UNLOCK(&curkey->Node_path);
723 if ( node->used_slots >= max_slots ) {
724 MEM_UNLOCK(&curkey->Node_path);
725 return( dberr(S_KEYERR) );
727 node_slot_ptr = &node->slots[slot_pos = np_ptr->slot*slot_len];
728 open_slots(node, slot_pos, 1);
730 /* copy brother into opened slot's child pointer */
731 bytecpy(node_slot_ptr + slot_len, &brother, sizeof(F_ADDR));
732 /* copy keyno into current slot */
733 bytecpy(node_slot_ptr + sizeof(F_ADDR), &prefix, sizeof(INT));
735 node_slot_ptr += key_data;
736 /* clear slot data area to zeros */
737 byteset(node_slot_ptr, 0, slot_len - key_data);
739 /* copy keyval into current slot */
740 if ( cfld_ptr->fd_type == CHARACTER && cfld_ptr->fd_dim[1] == 0 )
741 strncpy(node_slot_ptr, key_val, key_len);
743 bytecpy(node_slot_ptr, key_val, key_len);
745 /* copy database address into current slot */
746 bytecpy(node_slot_ptr + key_len, &dba, sizeof(DB_ADDR));
748 if ( node->used_slots == max_slots ) {
749 if ( pg == ROOT_ADDR )
752 split_node(pg, node);
757 MEM_UNLOCK(&curkey->Node_path);
763 /* Split node into two nodes
765 static int split_node(l_pg, l_node )
766 F_ADDR l_pg; /* left node's page number */
767 NODE FAR *l_node; /* left node buffer */
773 char FAR *l_node_slot_ptr;
775 /* extract middle key */
776 l_node_slot_ptr = &l_node->slots[mid_slot*slot_len];
777 bytecpy(&prefix, l_node_slot_ptr + sizeof(F_ADDR), sizeof(INT));
779 keyno = prefix + curr_db_table->key_offset;
781 fldno = key_info[keyno].fldno;
782 cfld_ptr = &field_table[fldno];
783 key_len = cfld_ptr->fd_len;
784 bytecpy(key_val, l_node_slot_ptr + key_data, key_len);
785 bytecpy(&dba, l_node_slot_ptr + key_data + key_len, sizeof(DB_ADDR));
787 /* divide left node */
788 l_node->used_slots = mid_slot;
790 /* allocate new right node */
791 if ((dio_pzalloc(keyfile, &r_pg) != S_OKAY) ||
792 (dio_get(r_pg, (char FAR * FAR *)&r_node, PGHOLD) != S_OKAY))
795 /* copy slots from left node at slot mid_slot+1 into right node */
796 r_node->used_slots = max_slots - (mid_slot + 1);
797 l_node_slot_ptr += slot_len;
798 bytecpy(r_node->slots, l_node_slot_ptr, NODE_WIDTH(r_node));
805 /* expand parent slot to include middle key and new right node ptr */
806 return( expand(key_val, dba, r_pg) );
812 static int split_root(node )
816 NODE FAR *l_node, FAR *r_node;
818 char FAR *node_slot_ptr;
820 /* allocate two new nodes */
821 if ((dio_pzalloc(keyfile, &l_pg) != S_OKAY) ||
822 (dio_pzalloc(keyfile, &r_pg) != S_OKAY) ||
823 (dio_get(l_pg, (char FAR * FAR *)&l_node, PGHOLD) != S_OKAY) ||
824 (dio_get(r_pg, (char FAR * FAR *)&r_node, PGHOLD) != S_OKAY))
827 /* copy 0..max_slots/2-1 keys from root into left node */
828 l_node->used_slots = mid_slot;
829 slot_pos = mid_slot*slot_len;
830 bytecpy(l_node->slots, node->slots, NODE_WIDTH(l_node));
832 /* copy max_slots/2+1..max_slots from root into right node */
833 r_node->used_slots = max_slots - (mid_slot + 1);
834 node_slot_ptr = &node->slots[slot_pos += slot_len];
835 bytecpy(r_node->slots, node_slot_ptr, NODE_WIDTH(r_node));
837 /* copy mid_slot into slot[0] of root */
838 bytecpy(node->slots, node_slot_ptr - slot_len, slot_len);
840 /* copy left page number into p[0] of root */
841 bytecpy(node->slots, &l_pg, sizeof(F_ADDR));
843 /* copy right page number into p[1] of root */
844 bytecpy(&node->slots[slot_len], &r_pg, sizeof(F_ADDR));
846 /* reset number of used slots in root */
847 node->used_slots = 1;
851 dio_touch(ROOT_ADDR);
858 /* Delete key from B-tree
861 key_delete(fld, key_val, dba )
863 char CONST FAR *key_val;
868 /* initialize key function operation */
869 if ( key_init(fld) != S_OKAY ) return( db_status );
871 /* locate key to be deleted */
872 if ((stat = key_locpos(key_val, &dba)) == S_OKAY) {
873 if ( (stat = delete()) == S_OKAY ) {
874 /* save key value and database address for possible repositioning */
875 MEM_LOCK(&curkey->Keyval);
876 bytecpy(curkey->keyval, key_val, key_len);
877 MEM_UNLOCK(&curkey->Keyval);
880 /* reset key position */
881 key_reset(curkey->keyfile);
884 return( db_status = stat );
889 /* Delete key at current node_path position
893 F_ADDR pg, p_pg, l_pg, r_pg;
899 NODE_PATH FAR *np_ptr;
900 char FAR *node_slot_ptr;
901 char FAR *p_node_slot_ptr;
902 char FAR *l_node_slot_ptr;
903 char FAR *r_node_slot_ptr;
905 MEM_LOCK(&curkey->Node_path);
906 np_ptr = &curkey->node_path[curkey->level];
908 /* read node containing key to be deleted */
909 if (dio_get(pg = np_ptr->node, (char FAR * FAR *)&node, PGHOLD) != S_OKAY) {
910 MEM_UNLOCK(&curkey->Node_path);
913 /* copy pointer to right sub-tree */
914 slot_pos = np_ptr->slot*slot_len;
915 node_slot_ptr = &node->slots[slot_pos];
916 bytecpy(&r_pg, node_slot_ptr + slot_len, sizeof(F_ADDR));
918 if ( r_pg != NULL_NODE ) {
919 /* find leftmost descendent of right sub-tree */
922 if ( dio_get(r_pg, (char FAR * FAR *)&r_node, NOPGHOLD) != S_OKAY ) {
923 MEM_UNLOCK(&curkey->Node_path);
930 bytecpy(&r_pg, r_node->slots, sizeof(F_ADDR));
931 } while ( r_pg != NULL_NODE );
933 /* copy key from leaf into node */
934 node_slot_ptr += sizeof(F_ADDR);
935 r_node_slot_ptr = &r_node->slots[sizeof(F_ADDR)];
936 bytecpy(node_slot_ptr, r_node_slot_ptr, slot_len - sizeof(F_ADDR));
939 /* set up to delete key from leaf */
940 /* (this is more efficient than a recursive call) */
942 node_slot_ptr = node->slots;
943 if (dio_get(pg = np_ptr->node, (char FAR * FAR *)&node, PGHOLD) != S_OKAY) {
944 MEM_UNLOCK(&curkey->Node_path);
948 shrink: /* delete key from leaf (shrink node ) */
949 close_slots(node, slot_pos, 1);
951 /* check if necessary to adjust nodes */
952 if ((curkey->level > 0) && (node->used_slots < mid_slot)) {
953 /* read in parent node */
954 if (dio_get(p_pg = (np_ptr - 1)->node, (char FAR * FAR *)&p_node,
956 MEM_UNLOCK(&curkey->Node_path);
959 slot_pos = (np_ptr - 1)->slot*slot_len;
960 node_slot_ptr = &node->slots[slot_pos];
961 if ((np_ptr - 1)->slot == p_node->used_slots ) {
962 /* pg is right node */
966 /* parent slot position should bisect left & right nodes */
967 --(np_ptr - 1)->slot;
968 slot_pos -= slot_len;
971 p_node_slot_ptr = &p_node->slots[slot_pos];
972 bytecpy(&l_pg, p_node_slot_ptr, sizeof(F_ADDR));
973 if ( dio_get(l_pg, (char FAR * FAR *)&l_node, PGHOLD) != S_OKAY ) {
974 MEM_UNLOCK(&curkey->Node_path);
979 /* pg is left node */
983 /* read right node */
984 p_node_slot_ptr = &p_node->slots[slot_pos + slot_len];
985 bytecpy(&r_pg, p_node_slot_ptr, sizeof(F_ADDR));
986 if (dio_get(r_pg, (char FAR * FAR *)&r_node, PGHOLD) != S_OKAY) {
987 MEM_UNLOCK(&curkey->Node_path);
991 if ((l_node->used_slots + r_node->used_slots + 1) < max_slots) {
992 /* combine left and right nodes */
993 if ((curkey->level == 1) && (p_node->used_slots == 1)) {
994 /* shrink down to root */
995 /* copy right node data into root */
996 p_node_slot_ptr = &p_node->slots[slot_len];
997 bytecpy(p_node_slot_ptr, r_node->slots, NODE_WIDTH(r_node));
998 p_node->used_slots = r_node->used_slots + 1;
999 r_node->used_slots = 0;
1002 /* copy left node data into root */
1003 open_slots(p_node, 0, l_node->used_slots);
1004 bytecpy(p_node->slots, l_node->slots, NODE_WIDTH(l_node));
1005 l_node->used_slots = 0;
1010 /* free node pages */
1011 dio_pzdel(keyfile, r_pg);
1012 dio_pzdel(keyfile, l_pg);
1013 MEM_UNLOCK(&curkey->Node_path);
1014 return( db_status );
1016 /* open space for l_node->used_slots+1 slots in right node */
1017 open_slots(r_node, 0, l_node->used_slots + 1);
1019 /* move left node slots into right node */
1020 amt = NODE_WIDTH(l_node);
1021 r_node_slot_ptr = r_node->slots;
1022 bytecpy(r_node_slot_ptr, l_node->slots, amt);
1024 /* move parent slot data into right node */
1025 r_node_slot_ptr += amt;
1026 p_node_slot_ptr = &p_node->slots[slot_pos + sizeof(F_ADDR)];
1027 bytecpy(r_node_slot_ptr, p_node_slot_ptr, slot_len - sizeof(F_ADDR));
1032 /* delete left node */
1033 l_node->used_slots = 0;
1034 if ( dio_pzdel(keyfile, l_pg) != S_OKAY ) {
1035 MEM_UNLOCK(&curkey->Node_path);
1036 return( db_status );
1038 /* decrement level & make parent node current node */
1043 goto shrink; /* delete slot from parent */
1045 /* acquire needed key from sibling */
1046 if ((l_node->used_slots + 1) < r_node->used_slots) {
1047 /* get key from right node */
1049 /* move parent slot to end of left node */
1050 l_node_slot_ptr = &l_node->slots[NODE_WIDTH(l_node)];
1051 p_node_slot_ptr = &p_node->slots[slot_pos + sizeof(F_ADDR)];
1052 bytecpy(l_node_slot_ptr, p_node_slot_ptr, slot_len - sizeof(F_ADDR));
1054 ++l_node->used_slots;
1056 /* copy slot 0 child from right node to left node orphan */
1057 l_node_slot_ptr += slot_len - sizeof(F_ADDR);
1058 r_node_slot_ptr = r_node->slots;
1059 bytecpy(l_node_slot_ptr, r_node_slot_ptr, sizeof(F_ADDR));
1061 /* move slot 0 of right node to parent */
1062 r_node_slot_ptr += sizeof(F_ADDR);
1063 bytecpy(p_node_slot_ptr, r_node_slot_ptr, slot_len - sizeof(F_ADDR));
1065 /* delete slot 0 from right node */
1066 close_slots(r_node, 0, 1);
1068 else if ((r_node->used_slots + 1) < l_node->used_slots) {
1069 /* get key from left node */
1071 /* open one slot at front of right node */
1072 open_slots(r_node, 0, 1);
1074 /* move parent slot to slot 0 of right node */
1075 r_node_slot_ptr = &r_node->slots[sizeof(F_ADDR)];
1076 p_node_slot_ptr = &p_node->slots[slot_pos + sizeof(F_ADDR)];
1077 bytecpy(r_node_slot_ptr, p_node_slot_ptr, slot_len - sizeof(F_ADDR));
1079 /* move end slot of left node to parent */
1080 l_node_slot_ptr = &l_node->slots[NODE_WIDTH(l_node) - slot_len];
1081 bytecpy(p_node_slot_ptr, l_node_slot_ptr, slot_len - sizeof(F_ADDR));
1083 /* move left orphan to child of slot 0 in right node */
1084 l_node_slot_ptr += slot_len - sizeof(F_ADDR);
1085 bytecpy(r_node->slots, l_node_slot_ptr, sizeof(F_ADDR));
1087 /* delete end slot from left node */
1088 --l_node->used_slots;
1097 MEM_UNLOCK(&curkey->Node_path);
1098 return( db_status );
1103 /* Open n slots in node
1105 static void open_slots(node, slot_pos, n)
1110 char FAR *dst, FAR *src;
1113 nw = NODE_WIDTH(node);
1115 src = &node->slots[nw];
1117 amt = nw - slot_pos;
1121 node->used_slots += n;
1126 /* Close n slots in node
1128 static void close_slots(node, slot_pos, n)
1133 char FAR *dst, FAR *src;
1136 node->used_slots -= n;
1139 dst = &node->slots[slot_pos];
1141 amt = NODE_WIDTH(node) - slot_pos;
1149 /* Read value of last key scanned
1152 d_keyread(key_val TASK_PARM)
1156 int kt_lc; /* loop control */
1163 FIELD_ENTRY FAR *fld_ptr;
1164 KEY_ENTRY FAR *key_ptr;
1166 DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(RECORD_IO));
1168 if ((curkey->lstat != KEYFOUND) &&
1169 (curkey->lstat != KEYNOTFOUND) &&
1170 (curkey->lstat != KEYREPOS)) {
1171 RETURN( dberr(S_KEYSEQ) );
1173 /* clear key area */
1174 byteset(key_val, '\0', cfld_ptr->fd_len);
1176 if ( cfld_ptr->fd_type == COMKEY ) {
1177 /* copy compound key fields */
1178 for (kt_lc = size_kt - cfld_ptr->fd_ptr,
1179 key_ptr = &key_table[cfld_ptr->fd_ptr];
1180 (--kt_lc >= 0) && (key_ptr->kt_key == fldno); ++key_ptr) {
1181 fld_ptr = &field_table[key_ptr->kt_field];
1182 fptr = key_type.ks.data + key_ptr->kt_ptr;
1183 kptr = key_val + key_ptr->kt_ptr;
1184 if ( key_ptr->kt_sort == 'd' ) {
1185 switch ( fld_ptr->fd_type ) {
1188 bytecpy(&fv, fptr, sizeof(float));
1189 fv = (float)0.0 - fv;
1190 bytecpy(kptr, &fv, sizeof(float));
1193 bytecpy(&dv, fptr, sizeof(double));
1195 bytecpy(kptr, &dv, sizeof(double));
1199 key_cmpcpy(kptr, fptr, fld_ptr->fd_len);
1200 if ( fld_ptr->fd_dim[0] > 1 && fld_ptr->fd_dim[1] == 0 ) {
1201 /* make sure a null byte is at the end */
1202 kptr[fld_ptr->fd_len-1] = '\0';
1206 key_cmpcpy(kptr, fptr, fld_ptr->fd_len);
1210 bytecpy(kptr, fptr, fld_ptr->fd_len);
1214 else if ( cfld_ptr->fd_type == CHARACTER && cfld_ptr->fd_dim[1] == 0 )
1215 strncpy(key_val, key_type.ks.data, key_len);
1217 bytecpy(key_val, key_type.ks.data, key_len);
1219 RETURN( db_status = S_OKAY );
1224 /* Build compound key value from record
1227 key_bldcom(fld, rec, key, cflag )
1228 int fld; /* compound key field number */
1229 char FAR *rec; /* ptr to record data */
1230 char FAR *key; /* ptr to array to recv constructed key */
1231 int cflag; /* TRUE to compliment compound descending keys */
1233 int kt_lc; /* loop control */
1239 FIELD_ENTRY FAR *fld_ptr, FAR *kfld_ptr;
1240 KEY_ENTRY FAR *key_ptr;
1242 /* clear key area */
1243 fld_ptr = &field_table[fld];
1244 byteset(key, '\0', fld_ptr->fd_len);
1246 /* create compound key value */
1247 rec -= record_table[fld_ptr->fd_rec].rt_data;
1248 for (kt_lc = size_kt - fld_ptr->fd_ptr,
1249 key_ptr = &key_table[fld_ptr->fd_ptr];
1250 (--kt_lc >= 0) && (key_ptr->kt_key == fld); ++key_ptr) {
1251 kfld_ptr = &field_table[key_ptr->kt_field];
1252 fptr = rec + kfld_ptr->fd_ptr;
1254 /* Complement descending keys if permitted (cflag) */
1255 if ( cflag && ( key_ptr->kt_sort == 'd' )) {
1256 switch ( kfld_ptr->fd_type ) {
1259 bytecpy(&fv, fptr, sizeof(float));
1260 fv = (float)0.0 - fv;
1261 bytecpy(&key[key_ptr->kt_ptr], &fv, sizeof(float));
1264 bytecpy(&dv, fptr, sizeof(double));
1266 bytecpy(&key[key_ptr->kt_ptr], &dv, sizeof(double));
1270 key_cmpcpy(key+key_ptr->kt_ptr, fptr, kfld_ptr->fd_len);
1271 if ( kfld_ptr->fd_dim[0] > 1 && kfld_ptr->fd_dim[1] == 0 ) {
1272 /* make sure a null byte is at the end */
1273 *(key + key_ptr->kt_ptr + kfld_ptr->fd_len - 1) = '\0';
1277 key_cmpcpy(key+key_ptr->kt_ptr, fptr, kfld_ptr->fd_len);
1281 bytecpy(&key[key_ptr->kt_ptr], fptr, kfld_ptr->fd_len);
1284 return( db_status = S_OKAY );
1289 /* Complement and copy bytes
1291 void key_cmpcpy(s1, s2, n)
1300 /* vpp -nOS2 -dUNIX -nBSD -nVANILLA_BSD -nVMS -nMEMLOCK -nWINDOWS -nFAR_ALLOC -f/usr/users/master/config/nonwin keyfcns.c */