1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1999-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/db_page.h" 13#include "dbinc/btree.h" 14#include "dbinc/qam.h" 15 16static int __bam_set_bt_minkey __P((DB *, u_int32_t)); 17static int __bam_get_bt_compare 18 __P((DB *, int (**)(DB *, const DBT *, const DBT *))); 19static int __bam_get_bt_prefix 20 __P((DB *, size_t(**)(DB *, const DBT *, const DBT *))); 21static int __bam_set_bt_prefix 22 __P((DB *, size_t(*)(DB *, const DBT *, const DBT *))); 23static int __bam_get_bt_compress __P((DB *, 24 int (**)(DB *, const DBT *, const DBT *, const DBT *, const DBT *, DBT *), 25 int (**)(DB *, const DBT *, const DBT *, DBT *, DBT *, DBT *))); 26static int __ram_get_re_delim __P((DB *, int *)); 27static int __ram_set_re_delim __P((DB *, int)); 28static int __ram_set_re_len __P((DB *, u_int32_t)); 29static int __ram_set_re_pad __P((DB *, int)); 30static int __ram_get_re_source __P((DB *, const char **)); 31static int __ram_set_re_source __P((DB *, const char *)); 32 33/* 34 * __bam_db_create -- 35 * Btree specific initialization of the DB structure. 36 * 37 * PUBLIC: int __bam_db_create __P((DB *)); 38 */ 39int 40__bam_db_create(dbp) 41 DB *dbp; 42{ 43 BTREE *t; 44 int ret; 45 46 /* Allocate and initialize the private btree structure. */ 47 if ((ret = __os_calloc(dbp->env, 1, sizeof(BTREE), &t)) != 0) 48 return (ret); 49 dbp->bt_internal = t; 50 51 t->bt_minkey = DEFMINKEYPAGE; /* Btree */ 52 t->bt_compare = __bam_defcmp; 53 t->bt_prefix = __bam_defpfx; 54#ifdef HAVE_COMPRESSION 55 t->bt_compress = NULL; 56 t->bt_decompress = NULL; 57 t->compress_dup_compare = NULL; 58 59 /* 60 * DB_AM_COMPRESS may have been set in __bam_metachk before the 61 * bt_internal structure existed. 62 */ 63 if (F_ISSET(dbp, DB_AM_COMPRESS) && 64 (ret = __bam_set_bt_compress(dbp, NULL, NULL)) != 0) 65 return (ret); 66#endif 67 68 dbp->get_bt_compare = __bam_get_bt_compare; 69 dbp->set_bt_compare = __bam_set_bt_compare; 70 dbp->get_bt_minkey = __bam_get_bt_minkey; 71 dbp->set_bt_minkey = __bam_set_bt_minkey; 72 dbp->get_bt_prefix = __bam_get_bt_prefix; 73 dbp->set_bt_prefix = __bam_set_bt_prefix; 74 dbp->get_bt_compress = __bam_get_bt_compress; 75 dbp->set_bt_compress = __bam_set_bt_compress; 76 77 t->re_pad = ' '; /* Recno */ 78 t->re_delim = '\n'; 79 t->re_eof = 1; 80 81 dbp->get_re_delim = __ram_get_re_delim; 82 dbp->set_re_delim = __ram_set_re_delim; 83 dbp->get_re_len = __ram_get_re_len; 84 dbp->set_re_len = __ram_set_re_len; 85 dbp->get_re_pad = __ram_get_re_pad; 86 dbp->set_re_pad = __ram_set_re_pad; 87 dbp->get_re_source = __ram_get_re_source; 88 dbp->set_re_source = __ram_set_re_source; 89 90 return (0); 91} 92 93/* 94 * __bam_db_close -- 95 * Btree specific discard of the DB structure. 96 * 97 * PUBLIC: int __bam_db_close __P((DB *)); 98 */ 99int 100__bam_db_close(dbp) 101 DB *dbp; 102{ 103 BTREE *t; 104 105 if ((t = dbp->bt_internal) == NULL) 106 return (0); 107 /* Recno */ 108 /* Close any backing source file descriptor. */ 109 if (t->re_fp != NULL) 110 (void)fclose(t->re_fp); 111 112 /* Free any backing source file name. */ 113 if (t->re_source != NULL) 114 __os_free(dbp->env, t->re_source); 115 116 __os_free(dbp->env, t); 117 dbp->bt_internal = NULL; 118 119 return (0); 120} 121 122/* 123 * __bam_map_flags -- 124 * Map Btree specific flags from public to the internal values. 125 * 126 * PUBLIC: void __bam_map_flags __P((DB *, u_int32_t *, u_int32_t *)); 127 */ 128void 129__bam_map_flags(dbp, inflagsp, outflagsp) 130 DB *dbp; 131 u_int32_t *inflagsp, *outflagsp; 132{ 133 COMPQUIET(dbp, NULL); 134 135 if (FLD_ISSET(*inflagsp, DB_DUP)) { 136 FLD_SET(*outflagsp, DB_AM_DUP); 137 FLD_CLR(*inflagsp, DB_DUP); 138 } 139 if (FLD_ISSET(*inflagsp, DB_DUPSORT)) { 140 FLD_SET(*outflagsp, DB_AM_DUP | DB_AM_DUPSORT); 141 FLD_CLR(*inflagsp, DB_DUPSORT); 142 } 143 if (FLD_ISSET(*inflagsp, DB_RECNUM)) { 144 FLD_SET(*outflagsp, DB_AM_RECNUM); 145 FLD_CLR(*inflagsp, DB_RECNUM); 146 } 147 if (FLD_ISSET(*inflagsp, DB_REVSPLITOFF)) { 148 FLD_SET(*outflagsp, DB_AM_REVSPLITOFF); 149 FLD_CLR(*inflagsp, DB_REVSPLITOFF); 150 } 151} 152 153/* 154 * __bam_set_flags -- 155 * Set Btree specific flags. 156 * 157 * PUBLIC: int __bam_set_flags __P((DB *, u_int32_t *flagsp)); 158 */ 159int 160__bam_set_flags(dbp, flagsp) 161 DB *dbp; 162 u_int32_t *flagsp; 163{ 164 BTREE *t; 165 u_int32_t flags; 166 167 t = dbp->bt_internal; 168 169 flags = *flagsp; 170 if (LF_ISSET(DB_DUP | DB_DUPSORT | DB_RECNUM | DB_REVSPLITOFF)) 171 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags"); 172 173 /* 174 * The DB_DUP and DB_DUPSORT flags are shared by the Hash 175 * and Btree access methods. 176 */ 177 if (LF_ISSET(DB_DUP | DB_DUPSORT)) 178 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH); 179 180 if (LF_ISSET(DB_RECNUM | DB_REVSPLITOFF)) 181 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); 182 183 /* DB_DUP/DB_DUPSORT is incompatible with DB_RECNUM. */ 184 if (LF_ISSET(DB_DUP | DB_DUPSORT) && F_ISSET(dbp, DB_AM_RECNUM)) 185 goto incompat; 186 187 /* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */ 188 if (LF_ISSET(DB_RECNUM) && F_ISSET(dbp, DB_AM_DUP)) 189 goto incompat; 190 191 /* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */ 192 if (LF_ISSET(DB_RECNUM) && LF_ISSET(DB_DUP | DB_DUPSORT)) 193 goto incompat; 194 195#ifdef HAVE_COMPRESSION 196 /* DB_RECNUM is incompatible with compression */ 197 if (LF_ISSET(DB_RECNUM) && DB_IS_COMPRESSED(dbp)) { 198 __db_errx(dbp->env, 199 "DB_RECNUM cannot be used with compression"); 200 return (EINVAL); 201 } 202 203 /* DB_DUP without DB_DUPSORT is incompatible with compression */ 204 if (LF_ISSET(DB_DUP) && !LF_ISSET(DB_DUPSORT) && 205 !F_ISSET(dbp, DB_AM_DUPSORT) && DB_IS_COMPRESSED(dbp)) { 206 __db_errx(dbp->env, 207 "DB_DUP cannot be used with compression without DB_DUPSORT"); 208 return (EINVAL); 209 } 210#endif 211 212 if (LF_ISSET(DB_DUPSORT) && dbp->dup_compare == NULL) { 213#ifdef HAVE_COMPRESSION 214 if (DB_IS_COMPRESSED(dbp)) { 215 dbp->dup_compare = __bam_compress_dupcmp; 216 t->compress_dup_compare = __bam_defcmp; 217 } else 218#endif 219 dbp->dup_compare = __bam_defcmp; 220 } 221 222 __bam_map_flags(dbp, flagsp, &dbp->flags); 223 return (0); 224 225incompat: 226 return (__db_ferr(dbp->env, "DB->set_flags", 1)); 227} 228 229/* 230 * __bam_get_bt_compare -- 231 * Get the comparison function. 232 */ 233static int 234__bam_get_bt_compare(dbp, funcp) 235 DB *dbp; 236 int (**funcp) __P((DB *, const DBT *, const DBT *)); 237{ 238 BTREE *t; 239 240 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); 241 242 t = dbp->bt_internal; 243 244 if (funcp != NULL) 245 *funcp = t->bt_compare; 246 247 return (0); 248} 249 250/* 251 * __bam_set_bt_compare -- 252 * Set the comparison function. 253 * 254 * PUBLIC: int __bam_set_bt_compare 255 * PUBLIC: __P((DB *, int (*)(DB *, const DBT *, const DBT *))); 256 */ 257int 258__bam_set_bt_compare(dbp, func) 259 DB *dbp; 260 int (*func) __P((DB *, const DBT *, const DBT *)); 261{ 262 BTREE *t; 263 264 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_compare"); 265 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); 266 267 t = dbp->bt_internal; 268 269 /* 270 * Can't default the prefix routine if the user supplies a comparison 271 * routine; shortening the keys can break their comparison algorithm. 272 */ 273 t->bt_compare = func; 274 if (t->bt_prefix == __bam_defpfx) 275 t->bt_prefix = NULL; 276 277 return (0); 278} 279 280/* 281 * __bam_get_bt_compress -- 282 * Get the compression functions. 283 */ 284static int 285__bam_get_bt_compress(dbp, compressp, decompressp) 286 DB *dbp; 287 int (**compressp) __P((DB *, const DBT *, const DBT *, const DBT *, 288 const DBT *, DBT *)); 289 int (**decompressp) __P((DB *, const DBT *, const DBT *, DBT *, DBT *, 290 DBT *)); 291{ 292#ifdef HAVE_COMPRESSION 293 BTREE *t; 294 295 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); 296 297 t = dbp->bt_internal; 298 299 if (compressp != NULL) 300 *compressp = t->bt_compress; 301 if (decompressp != NULL) 302 *decompressp = t->bt_decompress; 303 304 return (0); 305#else 306 COMPQUIET(compressp, NULL); 307 COMPQUIET(decompressp, NULL); 308 309 __db_errx(dbp->env, "compression support has not been compiled in"); 310 return (EINVAL); 311#endif 312} 313 314/* 315 * __bam_set_bt_compress -- 316 * Set the compression functions. 317 * 318 * PUBLIC: int __bam_set_bt_compress __P((DB *, 319 * PUBLIC: int (*)(DB *, const DBT *, const DBT *, 320 * PUBLIC: const DBT *, const DBT *, DBT *), 321 * PUBLIC: int (*)(DB *, const DBT *, const DBT *, DBT *, DBT *, DBT *))); 322 */ 323int 324__bam_set_bt_compress(dbp, compress, decompress) 325 DB *dbp; 326 int (*compress) __P((DB *, const DBT *, const DBT *, const DBT *, 327 const DBT *, DBT *)); 328 int (*decompress) __P((DB *, const DBT *, const DBT *, DBT *, DBT *, 329 DBT *)); 330{ 331#ifdef HAVE_COMPRESSION 332 BTREE *t; 333 334 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_compress"); 335 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); 336 337 t = dbp->bt_internal; 338 339 /* compression is incompatible with DB_RECNUM */ 340 if (F_ISSET(dbp, DB_AM_RECNUM)) { 341 __db_errx(dbp->env, 342 "compression cannot be used with DB_RECNUM"); 343 return (EINVAL); 344 } 345 346 /* compression is incompatible with DB_DUP without DB_DUPSORT */ 347 if (F_ISSET(dbp, DB_AM_DUP) && !F_ISSET(dbp, DB_AM_DUPSORT)) { 348 __db_errx(dbp->env, 349 "compression cannot be used with DB_DUP without DB_DUPSORT"); 350 return (EINVAL); 351 } 352 353 if (compress != 0 && decompress != 0) { 354 t->bt_compress = compress; 355 t->bt_decompress = decompress; 356 } else if (compress == 0 && decompress == 0) { 357 t->bt_compress = __bam_defcompress; 358 t->bt_decompress = __bam_defdecompress; 359 } else { 360 __db_errx(dbp->env, 361 "to enable compression you need to supply both function arguments"); 362 return (EINVAL); 363 } 364 F_SET(dbp, DB_AM_COMPRESS); 365 366 /* Copy dup_compare to compress_dup_compare, and use the compression 367 duplicate compare */ 368 if (F_ISSET(dbp, DB_AM_DUPSORT)) { 369 t->compress_dup_compare = dbp->dup_compare; 370 dbp->dup_compare = __bam_compress_dupcmp; 371 } 372 373 return (0); 374#else 375 COMPQUIET(compress, NULL); 376 COMPQUIET(decompress, NULL); 377 378 __db_errx(dbp->env, "compression support has not been compiled in"); 379 return (EINVAL); 380#endif 381} 382 383/* 384 * __db_get_bt_minkey -- 385 * Get the minimum keys per page. 386 * 387 * PUBLIC: int __bam_get_bt_minkey __P((DB *, u_int32_t *)); 388 */ 389int 390__bam_get_bt_minkey(dbp, bt_minkeyp) 391 DB *dbp; 392 u_int32_t *bt_minkeyp; 393{ 394 BTREE *t; 395 396 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); 397 398 t = dbp->bt_internal; 399 *bt_minkeyp = t->bt_minkey; 400 return (0); 401} 402 403/* 404 * __bam_set_bt_minkey -- 405 * Set the minimum keys per page. 406 */ 407static int 408__bam_set_bt_minkey(dbp, bt_minkey) 409 DB *dbp; 410 u_int32_t bt_minkey; 411{ 412 BTREE *t; 413 414 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_minkey"); 415 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); 416 417 t = dbp->bt_internal; 418 419 if (bt_minkey < 2) { 420 __db_errx(dbp->env, "minimum bt_minkey value is 2"); 421 return (EINVAL); 422 } 423 424 t->bt_minkey = bt_minkey; 425 return (0); 426} 427 428/* 429 * __bam_get_bt_prefix -- 430 * Get the prefix function. 431 */ 432static int 433__bam_get_bt_prefix(dbp, funcp) 434 DB *dbp; 435 size_t (**funcp) __P((DB *, const DBT *, const DBT *)); 436{ 437 BTREE *t; 438 439 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); 440 441 t = dbp->bt_internal; 442 if (funcp != NULL) 443 *funcp = t->bt_prefix; 444 return (0); 445} 446 447/* 448 * __bam_set_bt_prefix -- 449 * Set the prefix function. 450 */ 451static int 452__bam_set_bt_prefix(dbp, func) 453 DB *dbp; 454 size_t (*func) __P((DB *, const DBT *, const DBT *)); 455{ 456 BTREE *t; 457 458 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_prefix"); 459 DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); 460 461 t = dbp->bt_internal; 462 463 t->bt_prefix = func; 464 return (0); 465} 466 467/* 468 * __bam_copy_config 469 * Copy the configuration of one DB handle to another. 470 * PUBLIC: void __bam_copy_config __P((DB *, DB*, u_int32_t)); 471 */ 472void 473__bam_copy_config(src, dst, nparts) 474 DB *src, *dst; 475 u_int32_t nparts; 476{ 477 BTREE *s, *d; 478 479 COMPQUIET(nparts, 0); 480 481 s = src->bt_internal; 482 d = dst->bt_internal; 483 d->bt_compare = s->bt_compare; 484 d->bt_minkey = s->bt_minkey; 485 d->bt_minkey = s->bt_minkey; 486 d->bt_prefix = s->bt_prefix; 487#ifdef HAVE_COMPRESSION 488 d->bt_compress = s->bt_compress; 489 d->bt_decompress = s->bt_decompress; 490 d->compress_dup_compare = s->compress_dup_compare; 491#endif 492} 493 494/* 495 * __ram_map_flags -- 496 * Map Recno specific flags from public to the internal values. 497 * 498 * PUBLIC: void __ram_map_flags __P((DB *, u_int32_t *, u_int32_t *)); 499 */ 500void 501__ram_map_flags(dbp, inflagsp, outflagsp) 502 DB *dbp; 503 u_int32_t *inflagsp, *outflagsp; 504{ 505 COMPQUIET(dbp, NULL); 506 507 if (FLD_ISSET(*inflagsp, DB_RENUMBER)) { 508 FLD_SET(*outflagsp, DB_AM_RENUMBER); 509 FLD_CLR(*inflagsp, DB_RENUMBER); 510 } 511 if (FLD_ISSET(*inflagsp, DB_SNAPSHOT)) { 512 FLD_SET(*outflagsp, DB_AM_SNAPSHOT); 513 FLD_CLR(*inflagsp, DB_SNAPSHOT); 514 } 515} 516 517/* 518 * __ram_set_flags -- 519 * Set Recno specific flags. 520 * 521 * PUBLIC: int __ram_set_flags __P((DB *, u_int32_t *flagsp)); 522 */ 523int 524__ram_set_flags(dbp, flagsp) 525 DB *dbp; 526 u_int32_t *flagsp; 527{ 528 u_int32_t flags; 529 530 flags = *flagsp; 531 if (LF_ISSET(DB_RENUMBER | DB_SNAPSHOT)) { 532 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags"); 533 DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); 534 } 535 536 __ram_map_flags(dbp, flagsp, &dbp->flags); 537 return (0); 538} 539 540/* 541 * __db_get_re_delim -- 542 * Get the variable-length input record delimiter. 543 */ 544static int 545__ram_get_re_delim(dbp, re_delimp) 546 DB *dbp; 547 int *re_delimp; 548{ 549 BTREE *t; 550 551 DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); 552 t = dbp->bt_internal; 553 *re_delimp = t->re_delim; 554 return (0); 555} 556 557/* 558 * __ram_set_re_delim -- 559 * Set the variable-length input record delimiter. 560 */ 561static int 562__ram_set_re_delim(dbp, re_delim) 563 DB *dbp; 564 int re_delim; 565{ 566 BTREE *t; 567 568 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_delim"); 569 DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); 570 571 t = dbp->bt_internal; 572 573 t->re_delim = re_delim; 574 F_SET(dbp, DB_AM_DELIMITER); 575 576 return (0); 577} 578 579/* 580 * __db_get_re_len -- 581 * Get the variable-length input record length. 582 * 583 * PUBLIC: int __ram_get_re_len __P((DB *, u_int32_t *)); 584 */ 585int 586__ram_get_re_len(dbp, re_lenp) 587 DB *dbp; 588 u_int32_t *re_lenp; 589{ 590 BTREE *t; 591 QUEUE *q; 592 593 DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); 594 595 /* 596 * This has to work for all access methods, before or after opening the 597 * database. When the record length is set with __ram_set_re_len, the 598 * value in both the BTREE and QUEUE structs will be correct. 599 * Otherwise, this only makes sense after the database in opened, in 600 * which case we know the type. 601 */ 602 if (dbp->type == DB_QUEUE) { 603 q = dbp->q_internal; 604 *re_lenp = q->re_len; 605 } else { 606 t = dbp->bt_internal; 607 *re_lenp = t->re_len; 608 } 609 610 return (0); 611} 612 613/* 614 * __ram_set_re_len -- 615 * Set the variable-length input record length. 616 */ 617static int 618__ram_set_re_len(dbp, re_len) 619 DB *dbp; 620 u_int32_t re_len; 621{ 622 BTREE *t; 623 QUEUE *q; 624 625 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_len"); 626 DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); 627 628 t = dbp->bt_internal; 629 t->re_len = re_len; 630 631 q = dbp->q_internal; 632 q->re_len = re_len; 633 634 F_SET(dbp, DB_AM_FIXEDLEN); 635 636 return (0); 637} 638 639/* 640 * __db_get_re_pad -- 641 * Get the fixed-length record pad character. 642 * 643 * PUBLIC: int __ram_get_re_pad __P((DB *, int *)); 644 */ 645int 646__ram_get_re_pad(dbp, re_padp) 647 DB *dbp; 648 int *re_padp; 649{ 650 BTREE *t; 651 QUEUE *q; 652 653 DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); 654 655 /* 656 * This has to work for all access methods, before or after opening the 657 * database. When the record length is set with __ram_set_re_pad, the 658 * value in both the BTREE and QUEUE structs will be correct. 659 * Otherwise, this only makes sense after the database in opened, in 660 * which case we know the type. 661 */ 662 if (dbp->type == DB_QUEUE) { 663 q = dbp->q_internal; 664 *re_padp = q->re_pad; 665 } else { 666 t = dbp->bt_internal; 667 *re_padp = t->re_pad; 668 } 669 670 return (0); 671} 672 673/* 674 * __ram_set_re_pad -- 675 * Set the fixed-length record pad character. 676 */ 677static int 678__ram_set_re_pad(dbp, re_pad) 679 DB *dbp; 680 int re_pad; 681{ 682 BTREE *t; 683 QUEUE *q; 684 685 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_pad"); 686 DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); 687 688 t = dbp->bt_internal; 689 t->re_pad = re_pad; 690 691 q = dbp->q_internal; 692 q->re_pad = re_pad; 693 694 F_SET(dbp, DB_AM_PAD); 695 696 return (0); 697} 698 699/* 700 * __db_get_re_source -- 701 * Get the backing source file name. 702 */ 703static int 704__ram_get_re_source(dbp, re_sourcep) 705 DB *dbp; 706 const char **re_sourcep; 707{ 708 BTREE *t; 709 710 DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); 711 712 t = dbp->bt_internal; 713 *re_sourcep = t->re_source; 714 return (0); 715} 716 717/* 718 * __ram_set_re_source -- 719 * Set the backing source file name. 720 */ 721static int 722__ram_set_re_source(dbp, re_source) 723 DB *dbp; 724 const char *re_source; 725{ 726 BTREE *t; 727 728 DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_source"); 729 DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); 730 731 t = dbp->bt_internal; 732 733 return (__os_strdup(dbp->env, re_source, &t->re_source)); 734} 735