1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996-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/hash.h" 15#ifndef HAVE_QUEUE 16#include "dbinc/qam.h" /* For __db_no_queue_am(). */ 17#endif 18#include "dbinc/lock.h" 19#include "dbinc/log.h" 20#include "dbinc/mp.h" 21#include "dbinc/partition.h" 22#include "dbinc/txn.h" 23 24static int __db_associate_arg __P((DB *, DB *, 25 int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t)); 26static int __dbc_del_arg __P((DBC *, u_int32_t)); 27static int __dbc_pget_arg __P((DBC *, DBT *, u_int32_t)); 28static int __dbc_put_arg __P((DBC *, DBT *, DBT *, u_int32_t)); 29static int __db_curinval __P((const ENV *)); 30static int __db_cursor_arg __P((DB *, u_int32_t)); 31static int __db_del_arg __P((DB *, DBT *, u_int32_t)); 32static int __db_get_arg __P((const DB *, DBT *, DBT *, u_int32_t)); 33static int __db_join_arg __P((DB *, DBC **, u_int32_t)); 34static int __db_open_arg __P((DB *, 35 DB_TXN *, const char *, const char *, DBTYPE, u_int32_t)); 36static int __db_pget_arg __P((DB *, DBT *, u_int32_t)); 37static int __db_put_arg __P((DB *, DBT *, DBT *, u_int32_t)); 38static int __dbt_ferr __P((const DB *, const char *, const DBT *, int)); 39static int __db_associate_foreign_arg __P((DB *, DB *, 40 int (*)(DB *, const DBT *, DBT *, const DBT *, int *), 41 u_int32_t)); 42 43/* 44 * These functions implement the Berkeley DB API. They are organized in a 45 * layered fashion. The interface functions (XXX_pp) perform all generic 46 * error checks (for example, PANIC'd region, replication state change 47 * in progress, inconsistent transaction usage), call function-specific 48 * check routines (_arg) to check for proper flag usage, etc., do pre-amble 49 * processing (incrementing handle counts, handling local transactions), 50 * call the function and then do post-amble processing (local transactions, 51 * decrement handle counts). 52 * 53 * The basic structure is: 54 * Check for simple/generic errors (PANIC'd region) 55 * Check if replication is changing state (increment handle count). 56 * Call function-specific argument checking routine 57 * Create internal transaction if necessary 58 * Call underlying worker function 59 * Commit/abort internal transaction if necessary 60 * Decrement handle count 61 */ 62 63/* 64 * __db_associate_pp -- 65 * DB->associate pre/post processing. 66 * 67 * PUBLIC: int __db_associate_pp __P((DB *, DB_TXN *, DB *, 68 * PUBLIC: int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t)); 69 */ 70int 71__db_associate_pp(dbp, txn, sdbp, callback, flags) 72 DB *dbp, *sdbp; 73 DB_TXN *txn; 74 int (*callback) __P((DB *, const DBT *, const DBT *, DBT *)); 75 u_int32_t flags; 76{ 77 DBC *sdbc; 78 DB_THREAD_INFO *ip; 79 ENV *env; 80 int handle_check, ret, t_ret, txn_local; 81 82 env = dbp->env; 83 txn_local = 0; 84 85 STRIP_AUTO_COMMIT(flags); 86 87 ENV_ENTER(env, ip); 88 89 /* Check for replication block. */ 90 handle_check = IS_ENV_REPLICATED(env); 91 if (handle_check && 92 (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) { 93 handle_check = 0; 94 goto err; 95 } 96 97 /* 98 * Secondary cursors may have the primary's lock file ID, so we need 99 * to make sure that no older cursors are lying around when we make 100 * the transition. 101 */ 102 if (TAILQ_FIRST(&sdbp->active_queue) != NULL || 103 TAILQ_FIRST(&sdbp->join_queue) != NULL) { 104 __db_errx(env, 105 "Databases may not become secondary indices while cursors are open"); 106 ret = EINVAL; 107 goto err; 108 } 109 110 if ((ret = __db_associate_arg(dbp, sdbp, callback, flags)) != 0) 111 goto err; 112 113 /* 114 * Create a local transaction as necessary, check for consistent 115 * transaction usage, and, if we have no transaction but do have 116 * locking on, acquire a locker id for the handle lock acquisition. 117 */ 118 if (IS_DB_AUTO_COMMIT(dbp, txn)) { 119 if ((ret = __txn_begin(env, ip, NULL, &txn, 0)) != 0) 120 goto err; 121 txn_local = 1; 122 } 123 124 /* Check for consistent transaction usage. */ 125 if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0) 126 goto err; 127 128 while ((sdbc = TAILQ_FIRST(&sdbp->free_queue)) != NULL) 129 if ((ret = __dbc_destroy(sdbc)) != 0) 130 goto err; 131 132 ret = __db_associate(dbp, ip, txn, sdbp, callback, flags); 133 134err: if (txn_local && 135 (t_ret = __db_txn_auto_resolve(env, txn, 0, ret)) && ret == 0) 136 ret = t_ret; 137 138 /* Release replication block. */ 139 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 140 ret = t_ret; 141 ENV_LEAVE(env, ip); 142 return (ret); 143} 144 145/* 146 * __db_associate_arg -- 147 * Check DB->associate arguments. 148 */ 149static int 150__db_associate_arg(dbp, sdbp, callback, flags) 151 DB *dbp, *sdbp; 152 int (*callback) __P((DB *, const DBT *, const DBT *, DBT *)); 153 u_int32_t flags; 154{ 155 ENV *env; 156 int ret; 157 158 env = dbp->env; 159 160 if (F_ISSET(sdbp, DB_AM_SECONDARY)) { 161 __db_errx(env, 162 "Secondary index handles may not be re-associated"); 163 return (EINVAL); 164 } 165 if (F_ISSET(dbp, DB_AM_SECONDARY)) { 166 __db_errx(env, 167 "Secondary indices may not be used as primary databases"); 168 return (EINVAL); 169 } 170 if (F_ISSET(dbp, DB_AM_DUP)) { 171 __db_errx(env, 172 "Primary databases may not be configured with duplicates"); 173 return (EINVAL); 174 } 175 if (F_ISSET(dbp, DB_AM_RENUMBER)) { 176 __db_errx(env, 177 "Renumbering recno databases may not be used as primary databases"); 178 return (EINVAL); 179 } 180 181 /* 182 * It's OK for the primary and secondary to not share an environment IFF 183 * the environments are local to the DB handle. (Specifically, cursor 184 * adjustment will work correctly in this case.) The environment being 185 * local implies the environment is not configured for either locking or 186 * transactions, as neither of those could work correctly. 187 */ 188 if (dbp->env != sdbp->env && 189 (!F_ISSET(dbp->env, ENV_DBLOCAL) || 190 !F_ISSET(sdbp->env, ENV_DBLOCAL))) { 191 __db_errx(env, 192 "The primary and secondary must be opened in the same environment"); 193 return (EINVAL); 194 } 195 if ((DB_IS_THREADED(dbp) && !DB_IS_THREADED(sdbp)) || 196 (!DB_IS_THREADED(dbp) && DB_IS_THREADED(sdbp))) { 197 __db_errx(env, 198 "The DB_THREAD setting must be the same for primary and secondary"); 199 return (EINVAL); 200 } 201 if (callback == NULL && 202 (!F_ISSET(dbp, DB_AM_RDONLY) || !F_ISSET(sdbp, DB_AM_RDONLY))) { 203 __db_errx(env, 204 "Callback function may be NULL only when database handles are read-only"); 205 return (EINVAL); 206 } 207 208 if ((ret = __db_fchk(env, "DB->associate", flags, DB_CREATE | 209 DB_IMMUTABLE_KEY)) != 0) 210 return (ret); 211 212 return (0); 213} 214 215/* 216 * __db_close_pp -- 217 * DB->close pre/post processing. 218 * 219 * PUBLIC: int __db_close_pp __P((DB *, u_int32_t)); 220 */ 221int 222__db_close_pp(dbp, flags) 223 DB *dbp; 224 u_int32_t flags; 225{ 226 DB_THREAD_INFO *ip; 227 ENV *env; 228 int handle_check, ret, t_ret; 229 230 env = dbp->env; 231 ret = 0; 232 233 /* 234 * Close a DB handle -- as a handle destructor, we can't fail. 235 * 236 * !!! 237 * The actual argument checking is simple, do it inline, outside of 238 * the replication block. 239 */ 240 if (flags != 0 && flags != DB_NOSYNC) 241 ret = __db_ferr(env, "DB->close", 0); 242 243 ENV_ENTER(env, ip); 244 245 /* Check for replication block. */ 246 handle_check = IS_ENV_REPLICATED(env); 247 if (handle_check && (t_ret = __db_rep_enter(dbp, 0, 0, 0)) != 0) { 248 handle_check = 0; 249 if (ret == 0) 250 ret = t_ret; 251 } 252 253 if ((t_ret = __db_close(dbp, NULL, flags)) != 0 && ret == 0) 254 ret = t_ret; 255 256 /* Release replication block. */ 257 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 258 ret = t_ret; 259 260 ENV_LEAVE(env, ip); 261 return (ret); 262} 263 264/* 265 * __db_cursor_pp -- 266 * DB->cursor pre/post processing. 267 * 268 * PUBLIC: int __db_cursor_pp __P((DB *, DB_TXN *, DBC **, u_int32_t)); 269 */ 270int 271__db_cursor_pp(dbp, txn, dbcp, flags) 272 DB *dbp; 273 DB_TXN *txn; 274 DBC **dbcp; 275 u_int32_t flags; 276{ 277 DB_THREAD_INFO *ip; 278 ENV *env; 279 REGENV *renv; 280 int rep_blocked, ret; 281 282 env = dbp->env; 283 284 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->cursor"); 285 286 ENV_ENTER(env, ip); 287 288 /* Check for replication block. */ 289 rep_blocked = 0; 290 if (txn == NULL && IS_ENV_REPLICATED(env)) { 291 if ((ret = __op_rep_enter(env)) != 0) 292 goto err; 293 rep_blocked = 1; 294 renv = env->reginfo->primary; 295 if (dbp->timestamp != renv->rep_timestamp) { 296 __db_errx(env, "%s %s", 297 "replication recovery unrolled committed transactions;", 298 "open DB and DBcursor handles must be closed"); 299 ret = DB_REP_HANDLE_DEAD; 300 goto err; 301 } 302 } 303 if ((ret = __db_cursor_arg(dbp, flags)) != 0) 304 goto err; 305 306 /* 307 * Check for consistent transaction usage. For now, assume this 308 * cursor might be used for read operations only (in which case 309 * it may not require a txn). We'll check more stringently in 310 * c_del and c_put. (Note this means the read-op txn tests have 311 * to be a subset of the write-op ones.) 312 */ 313 if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0) 314 goto err; 315 316 ret = __db_cursor(dbp, ip, txn, dbcp, flags); 317 318err: /* Release replication block on error. */ 319 if (ret != 0 && rep_blocked) 320 (void)__op_rep_exit(env); 321 322 ENV_LEAVE(env, ip); 323 return (ret); 324} 325 326/* 327 * __db_cursor -- 328 * DB->cursor. 329 * 330 * PUBLIC: int __db_cursor __P((DB *, 331 * PUBLIC: DB_THREAD_INFO *, DB_TXN *, DBC **, u_int32_t)); 332 */ 333int 334__db_cursor(dbp, ip, txn, dbcp, flags) 335 DB *dbp; 336 DB_THREAD_INFO *ip; 337 DB_TXN *txn; 338 DBC **dbcp; 339 u_int32_t flags; 340{ 341 DBC *dbc; 342 ENV *env; 343 db_lockmode_t mode; 344 int ret; 345 346 env = dbp->env; 347 348 if (MULTIVERSION(dbp) && txn == NULL && (LF_ISSET(DB_TXN_SNAPSHOT) || 349 F_ISSET(env->dbenv, DB_ENV_TXN_SNAPSHOT))) { 350 if ((ret = 351 __txn_begin(env, ip, NULL, &txn, DB_TXN_SNAPSHOT)) != 0) 352 return (ret); 353 F_SET(txn, TXN_PRIVATE); 354 } 355 356 if ((ret = __db_cursor_int(dbp, ip, txn, dbp->type, PGNO_INVALID, 357 LF_ISSET(DB_CURSOR_BULK | DB_CURSOR_TRANSIENT), NULL, &dbc)) != 0) 358 return (ret); 359 360 /* 361 * If this is CDB, do all the locking in the interface, which is 362 * right here. 363 */ 364 if (CDB_LOCKING(env)) { 365 mode = (LF_ISSET(DB_WRITELOCK)) ? DB_LOCK_WRITE : 366 ((LF_ISSET(DB_WRITECURSOR) || txn != NULL) ? 367 DB_LOCK_IWRITE : DB_LOCK_READ); 368 if ((ret = __lock_get(env, dbc->locker, 0, 369 &dbc->lock_dbt, mode, &dbc->mylock)) != 0) 370 goto err; 371 if (LF_ISSET(DB_WRITECURSOR)) 372 F_SET(dbc, DBC_WRITECURSOR); 373 if (LF_ISSET(DB_WRITELOCK)) 374 F_SET(dbc, DBC_WRITER); 375 } 376 377 if (LF_ISSET(DB_READ_UNCOMMITTED) || 378 (txn != NULL && F_ISSET(txn, TXN_READ_UNCOMMITTED))) 379 F_SET(dbc, DBC_READ_UNCOMMITTED); 380 381 if (LF_ISSET(DB_READ_COMMITTED) || 382 (txn != NULL && F_ISSET(txn, TXN_READ_COMMITTED))) 383 F_SET(dbc, DBC_READ_COMMITTED); 384 385 *dbcp = dbc; 386 return (0); 387 388err: (void)__dbc_close(dbc); 389 return (ret); 390} 391 392/* 393 * __db_cursor_arg -- 394 * Check DB->cursor arguments. 395 */ 396static int 397__db_cursor_arg(dbp, flags) 398 DB *dbp; 399 u_int32_t flags; 400{ 401 ENV *env; 402 403 env = dbp->env; 404 405 /* 406 * DB_READ_COMMITTED and DB_READ_UNCOMMITTED require locking. 407 */ 408 if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED)) { 409 if (!LOCKING_ON(env)) 410 return (__db_fnl(env, "DB->cursor")); 411 } 412 413 LF_CLR(DB_CURSOR_BULK | 414 DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_TXN_SNAPSHOT); 415 416 /* Check for invalid function flags. */ 417 if (LF_ISSET(DB_WRITECURSOR)) { 418 if (DB_IS_READONLY(dbp)) 419 return (__db_rdonly(env, "DB->cursor")); 420 if (!CDB_LOCKING(env)) 421 return (__db_ferr(env, "DB->cursor", 0)); 422 LF_CLR(DB_WRITECURSOR); 423 } else if (LF_ISSET(DB_WRITELOCK)) { 424 if (DB_IS_READONLY(dbp)) 425 return (__db_rdonly(env, "DB->cursor")); 426 LF_CLR(DB_WRITELOCK); 427 } 428 429 if (flags != 0) 430 return (__db_ferr(env, "DB->cursor", 0)); 431 432 return (0); 433} 434 435/* 436 * __db_del_pp -- 437 * DB->del pre/post processing. 438 * 439 * PUBLIC: int __db_del_pp __P((DB *, DB_TXN *, DBT *, u_int32_t)); 440 */ 441int 442__db_del_pp(dbp, txn, key, flags) 443 DB *dbp; 444 DB_TXN *txn; 445 DBT *key; 446 u_int32_t flags; 447{ 448 DB_THREAD_INFO *ip; 449 ENV *env; 450 int handle_check, ret, t_ret, txn_local; 451 452 env = dbp->env; 453 txn_local = 0; 454 455 STRIP_AUTO_COMMIT(flags); 456 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->del"); 457 458#ifdef CONFIG_TEST 459 if (IS_REP_MASTER(env)) 460 DB_TEST_WAIT(env, env->test_check); 461#endif 462 ENV_ENTER(env, ip); 463 464 /* Check for replication block. */ 465 handle_check = IS_ENV_REPLICATED(env); 466 if (handle_check && 467 (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) { 468 handle_check = 0; 469 goto err; 470 } 471 472 if ((ret = __db_del_arg(dbp, key, flags)) != 0) 473 goto err; 474 475 /* Create local transaction as necessary. */ 476 if (IS_DB_AUTO_COMMIT(dbp, txn)) { 477 if ((ret = __txn_begin(env, ip, NULL, &txn, 0)) != 0) 478 goto err; 479 txn_local = 1; 480 } 481 482 /* Check for consistent transaction usage. */ 483 if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0) 484 goto err; 485 486 ret = __db_del(dbp, ip, txn, key, flags); 487 488err: if (txn_local && 489 (t_ret = __db_txn_auto_resolve(env, txn, 0, ret)) && ret == 0) 490 ret = t_ret; 491 492 /* Release replication block. */ 493 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 494 ret = t_ret; 495 ENV_LEAVE(env, ip); 496 __dbt_userfree(env, key, NULL, NULL); 497 return (ret); 498} 499 500/* 501 * __db_del_arg -- 502 * Check DB->delete arguments. 503 */ 504static int 505__db_del_arg(dbp, key, flags) 506 DB *dbp; 507 DBT *key; 508 u_int32_t flags; 509{ 510 ENV *env; 511 int ret; 512 513 env = dbp->env; 514 515 /* Check for changes to a read-only tree. */ 516 if (DB_IS_READONLY(dbp)) 517 return (__db_rdonly(env, "DB->del")); 518 519 /* Check for invalid function flags. */ 520 switch (flags) { 521 case DB_CONSUME: 522 if (dbp->type != DB_QUEUE) 523 return (__db_ferr(env, "DB->del", 0)); 524 goto copy; 525 case DB_MULTIPLE: 526 case DB_MULTIPLE_KEY: 527 if (!F_ISSET(key, DB_DBT_BULK)) { 528 __db_errx(env, 529 "DB->del with DB_MULTIPLE(_KEY) requires multiple key records"); 530 return (EINVAL); 531 } 532 /* FALL THROUGH */ 533 case 0: 534copy: if ((ret = __dbt_usercopy(env, key)) != 0) 535 return (ret); 536 break; 537 default: 538 return (__db_ferr(env, "DB->del", 0)); 539 } 540 541 return (0); 542} 543 544/* 545 * __db_exists -- 546 * DB->exists implementation. 547 * 548 * PUBLIC: int __db_exists __P((DB *, DB_TXN *, DBT *, u_int32_t)); 549 */ 550int 551__db_exists(dbp, txn, key, flags) 552 DB *dbp; 553 DB_TXN *txn; 554 DBT *key; 555 u_int32_t flags; 556{ 557 DBT data; 558 int ret; 559 560 /* 561 * Most flag checking is done in the DB->get call, we only check for 562 * specific incompatibilities here. This saves making __get_arg 563 * aware of the exist method's API constraints. 564 */ 565 STRIP_AUTO_COMMIT(flags); 566 if ((ret = __db_fchk(dbp->env, "DB->exists", flags, 567 DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW)) != 0) 568 return (ret); 569 570 /* 571 * Configure a data DBT that returns no bytes so there's no copy 572 * of the data. 573 */ 574 memset(&data, 0, sizeof(data)); 575 data.dlen = 0; 576 data.flags = DB_DBT_PARTIAL | DB_DBT_USERMEM; 577 578 return (dbp->get(dbp, txn, key, &data, flags)); 579} 580 581/* 582 * db_fd_pp -- 583 * DB->fd pre/post processing. 584 * 585 * PUBLIC: int __db_fd_pp __P((DB *, int *)); 586 */ 587int 588__db_fd_pp(dbp, fdp) 589 DB *dbp; 590 int *fdp; 591{ 592 DB_FH *fhp; 593 DB_THREAD_INFO *ip; 594 ENV *env; 595 int handle_check, ret, t_ret; 596 597 env = dbp->env; 598 599 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->fd"); 600 601 ENV_ENTER(env, ip); 602 603 /* Check for replication block. */ 604 handle_check = IS_ENV_REPLICATED(env); 605 if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) 606 goto err; 607 608 /* 609 * !!! 610 * There's no argument checking to be done. 611 * 612 * !!! 613 * The actual method call is simple, do it inline. 614 * 615 * XXX 616 * Truly spectacular layering violation. 617 */ 618 if ((ret = __mp_xxx_fh(dbp->mpf, &fhp)) == 0) { 619 if (fhp == NULL) { 620 *fdp = -1; 621 __db_errx(env, 622 "Database does not have a valid file handle"); 623 ret = ENOENT; 624 } else 625 *fdp = fhp->fd; 626 } 627 628 /* Release replication block. */ 629 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 630 ret = t_ret; 631 632err: ENV_LEAVE(env, ip); 633 return (ret); 634} 635 636/* 637 * __db_get_pp -- 638 * DB->get pre/post processing. 639 * 640 * PUBLIC: int __db_get_pp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); 641 */ 642int 643__db_get_pp(dbp, txn, key, data, flags) 644 DB *dbp; 645 DB_TXN *txn; 646 DBT *key, *data; 647 u_int32_t flags; 648{ 649 DB_THREAD_INFO *ip; 650 ENV *env; 651 u_int32_t mode; 652 int handle_check, ignore_lease, ret, t_ret, txn_local; 653 654 env = dbp->env; 655 mode = 0; 656 txn_local = 0; 657 658 STRIP_AUTO_COMMIT(flags); 659 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get"); 660 661 ignore_lease = LF_ISSET(DB_IGNORE_LEASE) ? 1 : 0; 662 LF_CLR(DB_IGNORE_LEASE); 663 664 if ((ret = __db_get_arg(dbp, key, data, flags)) != 0) 665 return (ret); 666 667 ENV_ENTER(env, ip); 668 669 /* Check for replication block. */ 670 handle_check = IS_ENV_REPLICATED(env); 671 if (handle_check && 672 (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) { 673 handle_check = 0; 674 goto err; 675 } 676 677 if (LF_ISSET(DB_READ_UNCOMMITTED)) 678 mode = DB_READ_UNCOMMITTED; 679 else if ((flags & DB_OPFLAGS_MASK) == DB_CONSUME || 680 (flags & DB_OPFLAGS_MASK) == DB_CONSUME_WAIT) { 681 mode = DB_WRITELOCK; 682 if (IS_DB_AUTO_COMMIT(dbp, txn)) { 683 if ((ret = __txn_begin(env, ip, NULL, &txn, 0)) != 0) 684 goto err; 685 txn_local = 1; 686 } 687 } 688 689 /* Check for consistent transaction usage. */ 690 if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 691 mode == DB_WRITELOCK || LF_ISSET(DB_RMW) ? 0 : 1)) != 0) 692 goto err; 693 694 ret = __db_get(dbp, ip, txn, key, data, flags); 695 /* 696 * Check for master leases. 697 */ 698 if (ret == 0 && 699 IS_REP_MASTER(env) && IS_USING_LEASES(env) && !ignore_lease) 700 ret = __rep_lease_check(env, 1); 701 702err: if (txn_local && 703 (t_ret = __db_txn_auto_resolve(env, txn, 0, ret)) && ret == 0) 704 ret = t_ret; 705 706 /* Release replication block. */ 707 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 708 ret = t_ret; 709 710 ENV_LEAVE(env, ip); 711 __dbt_userfree(env, key, NULL, data); 712 return (ret); 713} 714 715/* 716 * __db_get -- 717 * DB->get. 718 * 719 * PUBLIC: int __db_get __P((DB *, 720 * PUBLIC: DB_THREAD_INFO *, DB_TXN *, DBT *, DBT *, u_int32_t)); 721 */ 722int 723__db_get(dbp, ip, txn, key, data, flags) 724 DB *dbp; 725 DB_THREAD_INFO *ip; 726 DB_TXN *txn; 727 DBT *key, *data; 728 u_int32_t flags; 729{ 730 DBC *dbc; 731 u_int32_t mode; 732 int ret, t_ret; 733 734 /* 735 * The DB_CURSOR_TRANSIENT flag indicates that we're just doing a single 736 * operation with this cursor, and that in case of error we don't need 737 * to restore it to its old position. Thus, we can perform the get 738 * without duplicating the cursor, saving some cycles in this common 739 * case. 740 */ 741 mode = DB_CURSOR_TRANSIENT; 742 if (LF_ISSET(DB_READ_UNCOMMITTED)) { 743 mode |= DB_READ_UNCOMMITTED; 744 LF_CLR(DB_READ_UNCOMMITTED); 745 } else if (LF_ISSET(DB_READ_COMMITTED)) { 746 mode |= DB_READ_COMMITTED; 747 LF_CLR(DB_READ_COMMITTED); 748 } else if ((flags & DB_OPFLAGS_MASK) == DB_CONSUME || 749 (flags & DB_OPFLAGS_MASK) == DB_CONSUME_WAIT) 750 mode |= DB_WRITELOCK; 751 752 if ((ret = __db_cursor(dbp, ip, txn, &dbc, mode)) != 0) 753 return (ret); 754 755 DEBUG_LREAD(dbc, txn, "DB->get", key, NULL, flags); 756 757 /* 758 * The semantics of bulk gets are different for DB->get vs DBC->get. 759 * Mark the cursor so the low-level bulk get routines know which 760 * behavior we want. 761 */ 762 F_SET(dbc, DBC_FROM_DB_GET); 763 764 /* 765 * SET_RET_MEM indicates that if key and/or data have no DBT 766 * flags set and DB manages the returned-data memory, that memory 767 * will belong to this handle, not to the underlying cursor. 768 */ 769 SET_RET_MEM(dbc, dbp); 770 771 if (LF_ISSET(~(DB_RMW | DB_MULTIPLE)) == 0) 772 LF_SET(DB_SET); 773 774#ifdef HAVE_PARTITION 775 if (F_ISSET(dbc, DBC_PARTITIONED)) 776 ret = __partc_get(dbc, key, data, flags); 777 else 778#endif 779 ret = __dbc_get(dbc, key, data, flags); 780 781 if (dbc != NULL && (t_ret = __dbc_close(dbc)) != 0 && ret == 0) 782 ret = t_ret; 783 784 return (ret); 785} 786 787/* 788 * __db_get_arg -- 789 * DB->get argument checking, used by both DB->get and DB->pget. 790 */ 791static int 792__db_get_arg(dbp, key, data, flags) 793 const DB *dbp; 794 DBT *key, *data; 795 u_int32_t flags; 796{ 797 ENV *env; 798 int dirty, multi, ret; 799 800 env = dbp->env; 801 802 /* 803 * Check for read-modify-write validity. DB_RMW doesn't make sense 804 * with CDB cursors since if you're going to write the cursor, you 805 * had to create it with DB_WRITECURSOR. Regardless, we check for 806 * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it. 807 * If this changes, confirm that DB does not itself set the DB_RMW 808 * flag in a path where CDB may have been configured. 809 */ 810 dirty = 0; 811 if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW)) { 812 if (!LOCKING_ON(env)) 813 return (__db_fnl(env, "DB->get")); 814 if ((ret = __db_fcchk(env, "DB->get", 815 flags, DB_READ_UNCOMMITTED, DB_READ_COMMITTED)) != 0) 816 return (ret); 817 if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED)) 818 dirty = 1; 819 LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW); 820 } 821 822 multi = 0; 823 if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) { 824 if (LF_ISSET(DB_MULTIPLE_KEY)) 825 goto multi_err; 826 multi = LF_ISSET(DB_MULTIPLE) ? 1 : 0; 827 LF_CLR(DB_MULTIPLE); 828 } 829 830 /* Check for invalid function flags. */ 831 switch (flags) { 832 case DB_GET_BOTH: 833 if ((ret = __dbt_usercopy(env, data)) != 0) 834 return (ret); 835 /* FALLTHROUGH */ 836 case 0: 837 if ((ret = __dbt_usercopy(env, key)) != 0) { 838 __dbt_userfree(env, key, NULL, data); 839 return (ret); 840 } 841 break; 842 case DB_SET_RECNO: 843 if (!F_ISSET(dbp, DB_AM_RECNUM)) 844 goto err; 845 if ((ret = __dbt_usercopy(env, key)) != 0) 846 return (ret); 847 break; 848 case DB_CONSUME: 849 case DB_CONSUME_WAIT: 850 if (dirty) { 851 __db_errx(env, 852 "%s is not supported with DB_CONSUME or DB_CONSUME_WAIT", 853 LF_ISSET(DB_READ_UNCOMMITTED) ? 854 "DB_READ_UNCOMMITTED" : "DB_READ_COMMITTED"); 855 return (EINVAL); 856 } 857 if (multi) 858multi_err: return (__db_ferr(env, "DB->get", 1)); 859 if (dbp->type == DB_QUEUE) 860 break; 861 /* FALLTHROUGH */ 862 default: 863err: return (__db_ferr(env, "DB->get", 0)); 864 } 865 866 /* 867 * Check for invalid key/data flags. 868 */ 869 if ((ret = 870 __dbt_ferr(dbp, "key", key, DB_RETURNS_A_KEY(dbp, flags))) != 0) 871 return (ret); 872 if ((ret = __dbt_ferr(dbp, "data", data, 1)) != 0) 873 return (ret); 874 875 if (multi) { 876 if (!F_ISSET(data, DB_DBT_USERMEM)) { 877 __db_errx(env, 878 "DB_MULTIPLE requires DB_DBT_USERMEM be set"); 879 return (EINVAL); 880 } 881 if (F_ISSET(key, DB_DBT_PARTIAL) || 882 F_ISSET(data, DB_DBT_PARTIAL)) { 883 __db_errx(env, 884 "DB_MULTIPLE does not support DB_DBT_PARTIAL"); 885 return (EINVAL); 886 } 887 if (data->ulen < 1024 || 888 data->ulen < dbp->pgsize || data->ulen % 1024 != 0) { 889 __db_errx(env, "%s%s", 890 "DB_MULTIPLE buffers must be ", 891 "aligned, at least page size and multiples of 1KB"); 892 return (EINVAL); 893 } 894 } 895 896 return (0); 897} 898 899/* 900 * __db_join_pp -- 901 * DB->join pre/post processing. 902 * 903 * PUBLIC: int __db_join_pp __P((DB *, DBC **, DBC **, u_int32_t)); 904 */ 905int 906__db_join_pp(primary, curslist, dbcp, flags) 907 DB *primary; 908 DBC **curslist, **dbcp; 909 u_int32_t flags; 910{ 911 DB_THREAD_INFO *ip; 912 ENV *env; 913 int handle_check, ret, t_ret; 914 915 env = primary->env; 916 917 ENV_ENTER(env, ip); 918 919 /* Check for replication block. */ 920 handle_check = IS_ENV_REPLICATED(env); 921 if (handle_check && (ret = 922 __db_rep_enter(primary, 1, 0, curslist[0]->txn != NULL)) != 0) { 923 handle_check = 0; 924 goto err; 925 } 926 927 if ((ret = __db_join_arg(primary, curslist, flags)) == 0) 928 ret = __db_join(primary, curslist, dbcp, flags); 929 930 /* Release replication block. */ 931 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 932 ret = t_ret; 933 934err: ENV_LEAVE(env, ip); 935 return (ret); 936} 937 938/* 939 * __db_join_arg -- 940 * Check DB->join arguments. 941 */ 942static int 943__db_join_arg(primary, curslist, flags) 944 DB *primary; 945 DBC **curslist; 946 u_int32_t flags; 947{ 948 DB_TXN *txn; 949 ENV *env; 950 int i; 951 952 env = primary->env; 953 954 switch (flags) { 955 case 0: 956 case DB_JOIN_NOSORT: 957 break; 958 default: 959 return (__db_ferr(env, "DB->join", 0)); 960 } 961 962 if (curslist == NULL || curslist[0] == NULL) { 963 __db_errx(env, 964 "At least one secondary cursor must be specified to DB->join"); 965 return (EINVAL); 966 } 967 968 txn = curslist[0]->txn; 969 for (i = 1; curslist[i] != NULL; i++) 970 if (curslist[i]->txn != txn) { 971 __db_errx(env, 972 "All secondary cursors must share the same transaction"); 973 return (EINVAL); 974 } 975 976 return (0); 977} 978 979/* 980 * __db_key_range_pp -- 981 * DB->key_range pre/post processing. 982 * 983 * PUBLIC: int __db_key_range_pp 984 * PUBLIC: __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); 985 */ 986int 987__db_key_range_pp(dbp, txn, key, kr, flags) 988 DB *dbp; 989 DB_TXN *txn; 990 DBT *key; 991 DB_KEY_RANGE *kr; 992 u_int32_t flags; 993{ 994 DBC *dbc; 995 DB_THREAD_INFO *ip; 996 ENV *env; 997 int handle_check, ret, t_ret; 998 999 env = dbp->env; 1000 1001 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->key_range"); 1002 1003 /* 1004 * !!! 1005 * The actual argument checking is simple, do it inline, outside of 1006 * the replication block. 1007 */ 1008 if (flags != 0) 1009 return (__db_ferr(env, "DB->key_range", 0)); 1010 1011 ENV_ENTER(env, ip); 1012 1013 /* Check for replication block. */ 1014 handle_check = IS_ENV_REPLICATED(env); 1015 if (handle_check && 1016 (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) { 1017 handle_check = 0; 1018 goto err; 1019 } 1020 1021 /* Check for consistent transaction usage. */ 1022 if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0) 1023 goto err; 1024 1025 /* 1026 * !!! 1027 * The actual method call is simple, do it inline. 1028 */ 1029 switch (dbp->type) { 1030 case DB_BTREE: 1031#ifndef HAVE_BREW 1032 if ((ret = __dbt_usercopy(env, key)) != 0) 1033 goto err; 1034 1035 /* Acquire a cursor. */ 1036 if ((ret = __db_cursor(dbp, ip, txn, &dbc, 0)) != 0) 1037 break; 1038 1039 DEBUG_LWRITE(dbc, NULL, "bam_key_range", NULL, NULL, 0); 1040#ifdef HAVE_PARTITION 1041 if (DB_IS_PARTITIONED(dbp)) 1042 ret = __part_key_range(dbc, key, kr, flags); 1043 else 1044#endif 1045 ret = __bam_key_range(dbc, key, kr, flags); 1046 1047 if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0) 1048 ret = t_ret; 1049 __dbt_userfree(env, key, NULL, NULL); 1050 break; 1051#else 1052 COMPQUIET(dbc, NULL); 1053 COMPQUIET(key, NULL); 1054 COMPQUIET(kr, NULL); 1055 /* FALLTHROUGH */ 1056#endif 1057 case DB_HASH: 1058 case DB_QUEUE: 1059 case DB_RECNO: 1060 ret = __dbh_am_chk(dbp, DB_OK_BTREE); 1061 break; 1062 case DB_UNKNOWN: 1063 default: 1064 ret = __db_unknown_type(env, "DB->key_range", dbp->type); 1065 break; 1066 } 1067 1068err: /* Release replication block. */ 1069 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 1070 ret = t_ret; 1071 1072 ENV_LEAVE(env, ip); 1073 return (ret); 1074} 1075 1076/* 1077 * __db_open_pp -- 1078 * DB->open pre/post processing. 1079 * 1080 * PUBLIC: int __db_open_pp __P((DB *, DB_TXN *, 1081 * PUBLIC: const char *, const char *, DBTYPE, u_int32_t, int)); 1082 */ 1083int 1084__db_open_pp(dbp, txn, fname, dname, type, flags, mode) 1085 DB *dbp; 1086 DB_TXN *txn; 1087 const char *fname, *dname; 1088 DBTYPE type; 1089 u_int32_t flags; 1090 int mode; 1091{ 1092 DB_THREAD_INFO *ip; 1093 ENV *env; 1094 int handle_check, nosync, remove_me, ret, t_ret, txn_local; 1095 1096 env = dbp->env; 1097 nosync = 1; 1098 handle_check = remove_me = txn_local = 0; 1099 1100 ENV_ENTER(env, ip); 1101 1102 /* 1103 * Save the file and database names and flags. We do this here 1104 * because we don't pass all of the flags down into the actual 1105 * DB->open method call, we strip DB_AUTO_COMMIT at this layer. 1106 */ 1107 if ((fname != NULL && 1108 (ret = __os_strdup(env, fname, &dbp->fname)) != 0)) 1109 goto err; 1110 if ((dname != NULL && 1111 (ret = __os_strdup(env, dname, &dbp->dname)) != 0)) 1112 goto err; 1113 dbp->open_flags = flags; 1114 1115 /* Save the current DB handle flags for refresh. */ 1116 dbp->orig_flags = dbp->flags; 1117 1118 /* Check for replication block. */ 1119 handle_check = IS_ENV_REPLICATED(env); 1120 if (handle_check && 1121 (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) { 1122 handle_check = 0; 1123 goto err; 1124 } 1125 1126 /* 1127 * Create local transaction as necessary, check for consistent 1128 * transaction usage. 1129 */ 1130 if (IS_ENV_AUTO_COMMIT(env, txn, flags)) { 1131 if ((ret = __db_txn_auto_init(env, ip, &txn)) != 0) 1132 goto err; 1133 txn_local = 1; 1134 } else if (txn != NULL && !TXN_ON(env) && 1135 (!CDB_LOCKING(env) || !F_ISSET(txn, TXN_CDSGROUP))) { 1136 ret = __db_not_txn_env(env); 1137 goto err; 1138 } 1139 LF_CLR(DB_AUTO_COMMIT); 1140 1141 /* 1142 * We check arguments after possibly creating a local transaction, 1143 * which is unusual -- the reason is some flags are illegal if any 1144 * kind of transaction is in effect. 1145 */ 1146 if ((ret = __db_open_arg(dbp, txn, fname, dname, type, flags)) == 0) 1147 if ((ret = __db_open(dbp, ip, txn, fname, dname, type, 1148 flags, mode, PGNO_BASE_MD)) != 0) 1149 goto txnerr; 1150 1151 /* 1152 * You can open the database that describes the subdatabases in the 1153 * rest of the file read-only. The content of each key's data is 1154 * unspecified and applications should never be adding new records 1155 * or updating existing records. However, during recovery, we need 1156 * to open these databases R/W so we can redo/undo changes in them. 1157 * Likewise, we need to open master databases read/write during 1158 * rename and remove so we can be sure they're fully sync'ed, so 1159 * we provide an override flag for the purpose. 1160 */ 1161 if (dname == NULL && !IS_RECOVERING(env) && !LF_ISSET(DB_RDONLY) && 1162 !LF_ISSET(DB_RDWRMASTER) && F_ISSET(dbp, DB_AM_SUBDB)) { 1163 __db_errx(env, 1164 "files containing multiple databases may only be opened read-only"); 1165 ret = EINVAL; 1166 goto txnerr; 1167 } 1168 1169 /* 1170 * Success: file creations have to be synchronous, otherwise we don't 1171 * care. 1172 */ 1173 if (F_ISSET(dbp, DB_AM_CREATED | DB_AM_CREATED_MSTR)) 1174 nosync = 0; 1175 1176 /* Success: don't discard the file on close. */ 1177 F_CLR(dbp, DB_AM_DISCARD | DB_AM_CREATED | DB_AM_CREATED_MSTR); 1178 1179 /* 1180 * If not transactional, remove the databases/subdatabases if it is 1181 * persistent. If we're transactional, the child transaction abort 1182 * cleans up. 1183 */ 1184txnerr: if (ret != 0 && !IS_REAL_TXN(txn)) { 1185 remove_me = (F_ISSET(dbp, DB_AM_CREATED) && 1186 (fname != NULL || dname != NULL)) ? 1 : 0; 1187 if (F_ISSET(dbp, DB_AM_CREATED_MSTR) || 1188 (dname == NULL && remove_me)) 1189 /* Remove file. */ 1190 (void)__db_remove_int(dbp, 1191 ip, txn, fname, NULL, DB_FORCE); 1192 else if (remove_me) 1193 /* Remove subdatabase. */ 1194 (void)__db_remove_int(dbp, 1195 ip, txn, fname, dname, DB_FORCE); 1196 } 1197 1198 if (txn_local && (t_ret = 1199 __db_txn_auto_resolve(env, txn, nosync, ret)) && ret == 0) 1200 ret = t_ret; 1201 1202err: /* Release replication block. */ 1203 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 1204 ret = t_ret; 1205 1206 ENV_LEAVE(env, ip); 1207 return (ret); 1208} 1209 1210/* 1211 * __db_open_arg -- 1212 * Check DB->open arguments. 1213 */ 1214static int 1215__db_open_arg(dbp, txn, fname, dname, type, flags) 1216 DB *dbp; 1217 DB_TXN *txn; 1218 const char *fname, *dname; 1219 DBTYPE type; 1220 u_int32_t flags; 1221{ 1222 ENV *env; 1223 u_int32_t ok_flags; 1224 int ret; 1225 1226 env = dbp->env; 1227 1228 /* Validate arguments. */ 1229#undef OKFLAGS 1230#define OKFLAGS \ 1231 (DB_AUTO_COMMIT | DB_CREATE | DB_EXCL | DB_FCNTL_LOCKING | \ 1232 DB_MULTIVERSION | DB_NOMMAP | DB_NO_AUTO_COMMIT | DB_RDONLY | \ 1233 DB_RDWRMASTER | DB_READ_UNCOMMITTED | DB_THREAD | DB_TRUNCATE) 1234 if ((ret = __db_fchk(env, "DB->open", flags, OKFLAGS)) != 0) 1235 return (ret); 1236 if (LF_ISSET(DB_EXCL) && !LF_ISSET(DB_CREATE)) 1237 return (__db_ferr(env, "DB->open", 1)); 1238 if (LF_ISSET(DB_RDONLY) && LF_ISSET(DB_CREATE)) 1239 return (__db_ferr(env, "DB->open", 1)); 1240 1241#ifdef HAVE_VXWORKS 1242 if (LF_ISSET(DB_TRUNCATE)) { 1243 __db_errx(env, "DB_TRUNCATE not supported on VxWorks"); 1244 return (DB_OPNOTSUP); 1245 } 1246#endif 1247 switch (type) { 1248 case DB_UNKNOWN: 1249 if (LF_ISSET(DB_CREATE|DB_TRUNCATE)) { 1250 __db_errx(env, 1251 "DB_UNKNOWN type specified with DB_CREATE or DB_TRUNCATE"); 1252 return (EINVAL); 1253 } 1254 ok_flags = 0; 1255 break; 1256 case DB_BTREE: 1257 ok_flags = DB_OK_BTREE; 1258 break; 1259 case DB_HASH: 1260#ifndef HAVE_HASH 1261 return (__db_no_hash_am(env)); 1262#endif 1263 ok_flags = DB_OK_HASH; 1264 break; 1265 case DB_QUEUE: 1266#ifndef HAVE_QUEUE 1267 return (__db_no_queue_am(env)); 1268#endif 1269 ok_flags = DB_OK_QUEUE; 1270 break; 1271 case DB_RECNO: 1272 ok_flags = DB_OK_RECNO; 1273 break; 1274 default: 1275 __db_errx(env, "unknown type: %lu", (u_long)type); 1276 return (EINVAL); 1277 } 1278 if (ok_flags) 1279 DB_ILLEGAL_METHOD(dbp, ok_flags); 1280 1281 /* The environment may have been created, but never opened. */ 1282 if (!F_ISSET(env, ENV_DBLOCAL | ENV_OPEN_CALLED)) { 1283 __db_errx(env, "database environment not yet opened"); 1284 return (EINVAL); 1285 } 1286 1287 /* 1288 * Historically, you could pass in an environment that didn't have a 1289 * mpool, and DB would create a private one behind the scenes. This 1290 * no longer works. 1291 */ 1292 if (!F_ISSET(env, ENV_DBLOCAL) && !MPOOL_ON(env)) { 1293 __db_errx(env, "environment did not include a memory pool"); 1294 return (EINVAL); 1295 } 1296 1297 /* 1298 * You can't specify threads during DB->open if subsystems in the 1299 * environment weren't configured with them. 1300 */ 1301 if (LF_ISSET(DB_THREAD) && !F_ISSET(env, ENV_DBLOCAL | ENV_THREAD)) { 1302 __db_errx(env, "environment not created using DB_THREAD"); 1303 return (EINVAL); 1304 } 1305 1306 /* DB_MULTIVERSION requires a database configured for transactions. */ 1307 if (LF_ISSET(DB_MULTIVERSION) && !IS_REAL_TXN(txn)) { 1308 __db_errx(env, 1309 "DB_MULTIVERSION illegal without a transaction specified"); 1310 return (EINVAL); 1311 } 1312 1313 if (LF_ISSET(DB_MULTIVERSION) && type == DB_QUEUE) { 1314 __db_errx(env, 1315 "DB_MULTIVERSION illegal with queue databases"); 1316 return (EINVAL); 1317 } 1318 1319 /* DB_TRUNCATE is neither transaction recoverable nor lockable. */ 1320 if (LF_ISSET(DB_TRUNCATE) && (LOCKING_ON(env) || txn != NULL)) { 1321 __db_errx(env, 1322 "DB_TRUNCATE illegal with %s specified", 1323 LOCKING_ON(env) ? "locking" : "transactions"); 1324 return (EINVAL); 1325 } 1326 1327 /* Subdatabase checks. */ 1328 if (dname != NULL) { 1329 /* QAM can only be done on in-memory subdatabases. */ 1330 if (type == DB_QUEUE && fname != NULL) { 1331 __db_errx( 1332 env, "Queue databases must be one-per-file"); 1333 return (EINVAL); 1334 } 1335 1336 /* 1337 * Named in-memory databases can't support certain flags, 1338 * so check here. 1339 */ 1340 if (fname == NULL) 1341 F_CLR(dbp, DB_AM_CHKSUM | DB_AM_ENCRYPT); 1342 } 1343 1344 return (0); 1345} 1346 1347/* 1348 * __db_pget_pp -- 1349 * DB->pget pre/post processing. 1350 * 1351 * PUBLIC: int __db_pget_pp 1352 * PUBLIC: __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t)); 1353 */ 1354int 1355__db_pget_pp(dbp, txn, skey, pkey, data, flags) 1356 DB *dbp; 1357 DB_TXN *txn; 1358 DBT *skey, *pkey, *data; 1359 u_int32_t flags; 1360{ 1361 DB_THREAD_INFO *ip; 1362 ENV *env; 1363 int handle_check, ignore_lease, ret, t_ret; 1364 1365 env = dbp->env; 1366 1367 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->pget"); 1368 1369 ignore_lease = LF_ISSET(DB_IGNORE_LEASE) ? 1 : 0; 1370 LF_CLR(DB_IGNORE_LEASE); 1371 1372 if ((ret = __db_pget_arg(dbp, pkey, flags)) != 0 || 1373 (ret = __db_get_arg(dbp, skey, data, flags)) != 0) { 1374 __dbt_userfree(env, skey, pkey, data); 1375 return (ret); 1376 } 1377 1378 ENV_ENTER(env, ip); 1379 1380 /* Check for replication block. */ 1381 handle_check = IS_ENV_REPLICATED(env); 1382 if (handle_check && 1383 (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) { 1384 handle_check = 0; 1385 goto err; 1386 } 1387 1388 ret = __db_pget(dbp, ip, txn, skey, pkey, data, flags); 1389 /* 1390 * Check for master leases. 1391 */ 1392 if (ret == 0 && 1393 IS_REP_MASTER(env) && IS_USING_LEASES(env) && !ignore_lease) 1394 ret = __rep_lease_check(env, 1); 1395 1396err: /* Release replication block. */ 1397 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 1398 ret = t_ret; 1399 1400 ENV_LEAVE(env, ip); 1401 __dbt_userfree(env, skey, pkey, data); 1402 return (ret); 1403} 1404 1405/* 1406 * __db_pget -- 1407 * DB->pget. 1408 * 1409 * PUBLIC: int __db_pget __P((DB *, 1410 * PUBLIC: DB_THREAD_INFO *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t)); 1411 */ 1412int 1413__db_pget(dbp, ip, txn, skey, pkey, data, flags) 1414 DB *dbp; 1415 DB_THREAD_INFO *ip; 1416 DB_TXN *txn; 1417 DBT *skey, *pkey, *data; 1418 u_int32_t flags; 1419{ 1420 DBC *dbc; 1421 u_int32_t mode; 1422 int ret, t_ret; 1423 1424 mode = DB_CURSOR_TRANSIENT; 1425 if (LF_ISSET(DB_READ_UNCOMMITTED)) { 1426 mode |= DB_READ_UNCOMMITTED; 1427 LF_CLR(DB_READ_UNCOMMITTED); 1428 } else if (LF_ISSET(DB_READ_COMMITTED)) { 1429 mode |= DB_READ_COMMITTED; 1430 LF_CLR(DB_READ_COMMITTED); 1431 } 1432 1433 if ((ret = __db_cursor(dbp, ip, txn, &dbc, mode)) != 0) 1434 return (ret); 1435 1436 SET_RET_MEM(dbc, dbp); 1437 1438 DEBUG_LREAD(dbc, txn, "__db_pget", skey, NULL, flags); 1439 1440 /* 1441 * !!! 1442 * The actual method call is simple, do it inline. 1443 * 1444 * The underlying cursor pget will fill in a default DBT for null 1445 * pkeys, and use the cursor's returned-key memory internally to 1446 * store any intermediate primary keys. However, we've just set 1447 * the returned-key memory to the DB handle's key memory, which 1448 * is unsafe to use if the DB handle is threaded. If the pkey 1449 * argument is NULL, use the DBC-owned returned-key memory 1450 * instead; it'll go away when we close the cursor before we 1451 * return, but in this case that's just fine, as we're not 1452 * returning the primary key. 1453 */ 1454 if (pkey == NULL) 1455 dbc->rkey = &dbc->my_rkey; 1456 1457 /* 1458 * The cursor is just a perfectly ordinary secondary database cursor. 1459 * Call its c_pget() method to do the dirty work. 1460 */ 1461 if (flags == 0 || flags == DB_RMW) 1462 flags |= DB_SET; 1463 1464 ret = __dbc_pget(dbc, skey, pkey, data, flags); 1465 1466 if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0) 1467 ret = t_ret; 1468 1469 return (ret); 1470} 1471 1472/* 1473 * __db_pget_arg -- 1474 * Check DB->pget arguments. 1475 */ 1476static int 1477__db_pget_arg(dbp, pkey, flags) 1478 DB *dbp; 1479 DBT *pkey; 1480 u_int32_t flags; 1481{ 1482 ENV *env; 1483 int ret; 1484 1485 env = dbp->env; 1486 1487 if (!F_ISSET(dbp, DB_AM_SECONDARY)) { 1488 __db_errx(env, 1489 "DB->pget may only be used on secondary indices"); 1490 return (EINVAL); 1491 } 1492 1493 if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) { 1494 __db_errx(env, 1495 "DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices"); 1496 return (EINVAL); 1497 } 1498 1499 /* DB_CONSUME makes no sense on a secondary index. */ 1500 LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW); 1501 switch (flags) { 1502 case DB_CONSUME: 1503 case DB_CONSUME_WAIT: 1504 return (__db_ferr(env, "DB->pget", 0)); 1505 default: 1506 /* __db_get_arg will catch the rest. */ 1507 break; 1508 } 1509 1510 /* 1511 * We allow the pkey field to be NULL, so that we can make the 1512 * two-DBT get calls into wrappers for the three-DBT ones. 1513 */ 1514 if (pkey != NULL && 1515 (ret = __dbt_ferr(dbp, "primary key", pkey, 1)) != 0) 1516 return (ret); 1517 1518 if (flags == DB_GET_BOTH) { 1519 /* The pkey field can't be NULL if we're doing a DB_GET_BOTH. */ 1520 if (pkey == NULL) { 1521 __db_errx(env, 1522 "DB_GET_BOTH on a secondary index requires a primary key"); 1523 return (EINVAL); 1524 } 1525 if ((ret = __dbt_usercopy(env, pkey)) != 0) 1526 return (ret); 1527 } 1528 1529 return (0); 1530} 1531 1532/* 1533 * __db_put_pp -- 1534 * DB->put pre/post processing. 1535 * 1536 * PUBLIC: int __db_put_pp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); 1537 */ 1538int 1539__db_put_pp(dbp, txn, key, data, flags) 1540 DB *dbp; 1541 DB_TXN *txn; 1542 DBT *key, *data; 1543 u_int32_t flags; 1544{ 1545 DB_THREAD_INFO *ip; 1546 ENV *env; 1547 int handle_check, ret, txn_local, t_ret; 1548 1549 env = dbp->env; 1550 txn_local = 0; 1551 1552 STRIP_AUTO_COMMIT(flags); 1553 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->put"); 1554 1555 if ((ret = __db_put_arg(dbp, key, data, flags)) != 0) 1556 return (ret); 1557 1558 ENV_ENTER(env, ip); 1559 1560 /* Check for replication block. */ 1561 handle_check = IS_ENV_REPLICATED(env); 1562 if (handle_check && 1563 (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) { 1564 handle_check = 0; 1565 goto err; 1566 } 1567 1568 /* Create local transaction as necessary. */ 1569 if (IS_DB_AUTO_COMMIT(dbp, txn)) { 1570 if ((ret = __txn_begin(env, ip, NULL, &txn, 0)) != 0) 1571 goto err; 1572 txn_local = 1; 1573 } 1574 1575 /* Check for consistent transaction usage. */ 1576 if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0) 1577 goto err; 1578 1579 ret = __db_put(dbp, ip, txn, key, data, flags); 1580 1581err: if (txn_local && 1582 (t_ret = __db_txn_auto_resolve(env, txn, 0, ret)) && ret == 0) 1583 ret = t_ret; 1584 1585 /* Release replication block. */ 1586 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 1587 ret = t_ret; 1588 1589 ENV_LEAVE(env, ip); 1590 __dbt_userfree(env, key, NULL, data); 1591 return (ret); 1592} 1593 1594/* 1595 * __db_put_arg -- 1596 * Check DB->put arguments. 1597 */ 1598static int 1599__db_put_arg(dbp, key, data, flags) 1600 DB *dbp; 1601 DBT *key, *data; 1602 u_int32_t flags; 1603{ 1604 ENV *env; 1605 int ret, returnkey; 1606 1607 env = dbp->env; 1608 returnkey = 0; 1609 1610 /* Check for changes to a read-only tree. */ 1611 if (DB_IS_READONLY(dbp)) 1612 return (__db_rdonly(env, "DB->put")); 1613 1614 /* Check for puts on a secondary. */ 1615 if (F_ISSET(dbp, DB_AM_SECONDARY)) { 1616 __db_errx(env, "DB->put forbidden on secondary indices"); 1617 return (EINVAL); 1618 } 1619 1620 if (LF_ISSET(DB_MULTIPLE_KEY | DB_MULTIPLE)) { 1621 if (LF_ISSET(DB_MULTIPLE) && LF_ISSET(DB_MULTIPLE_KEY)) 1622 goto err; 1623 1624 switch (LF_ISSET(DB_OPFLAGS_MASK)) { 1625 case 0: 1626 case DB_OVERWRITE_DUP: 1627 break; 1628 default: 1629 __db_errx(env, 1630 "DB->put: DB_MULTIPLE(_KEY) can only be combined with DB_OVERWRITE_DUP"); 1631 return (EINVAL); 1632 } 1633 1634 if (!F_ISSET(key, DB_DBT_BULK)) { 1635 __db_errx(env, 1636 "DB->put with DB_MULTIPLE(_KEY) requires a bulk key buffer"); 1637 return (EINVAL); 1638 } 1639 } 1640 if (LF_ISSET(DB_MULTIPLE)) { 1641 if (!F_ISSET(data, DB_DBT_BULK)) { 1642 __db_errx(env, 1643 "DB->put with DB_MULTIPLE requires a bulk data buffer"); 1644 return (EINVAL); 1645 } 1646 } 1647 1648 /* Check for invalid function flags. */ 1649 switch (LF_ISSET(DB_OPFLAGS_MASK)) { 1650 case 0: 1651 case DB_NOOVERWRITE: 1652 case DB_OVERWRITE_DUP: 1653 break; 1654 case DB_APPEND: 1655 if (dbp->type != DB_RECNO && dbp->type != DB_QUEUE) 1656 goto err; 1657 returnkey = 1; 1658 break; 1659 case DB_NODUPDATA: 1660 if (F_ISSET(dbp, DB_AM_DUPSORT)) 1661 break; 1662 /* FALLTHROUGH */ 1663 default: 1664err: return (__db_ferr(env, "DB->put", 0)); 1665 } 1666 1667 /* 1668 * Check for invalid key/data flags. The key may reasonably be NULL 1669 * if DB_APPEND is set and the application doesn't care about the 1670 * returned key. 1671 */ 1672 if (((returnkey && key != NULL) || !returnkey) && 1673 (ret = __dbt_ferr(dbp, "key", key, returnkey)) != 0) 1674 return (ret); 1675 if (!LF_ISSET(DB_MULTIPLE_KEY) && 1676 (ret = __dbt_ferr(dbp, "data", data, 0)) != 0) 1677 return (ret); 1678 1679 /* 1680 * The key parameter should not be NULL or have the "partial" flag set 1681 * in a put call unless the user doesn't care about a key value we'd 1682 * return. The user tells us they don't care about the returned key by 1683 * setting the key parameter to NULL or configuring the key DBT to not 1684 * return any information. (Returned keys from a put are always record 1685 * numbers, and returning part of a record number doesn't make sense: 1686 * only accept a partial return if the length returned is 0.) 1687 */ 1688 if ((returnkey && 1689 key != NULL && F_ISSET(key, DB_DBT_PARTIAL) && key->dlen != 0) || 1690 (!returnkey && F_ISSET(key, DB_DBT_PARTIAL))) 1691 return (__db_ferr(env, "key DBT", 0)); 1692 1693 /* Check for partial puts in the presence of duplicates. */ 1694 if (data != NULL && F_ISSET(data, DB_DBT_PARTIAL) && 1695 (F_ISSET(dbp, DB_AM_DUP) || F_ISSET(key, DB_DBT_DUPOK))) { 1696 __db_errx(env, 1697"a partial put in the presence of duplicates requires a cursor operation"); 1698 return (EINVAL); 1699 } 1700 1701 if ((flags != DB_APPEND && (ret = __dbt_usercopy(env, key)) != 0) || 1702 (!LF_ISSET(DB_MULTIPLE_KEY) && 1703 (ret = __dbt_usercopy(env, data)) != 0)) 1704 return (ret); 1705 1706 return (0); 1707} 1708 1709/* 1710 * __db_compact_pp -- 1711 * DB->compact pre/post processing. 1712 * 1713 * PUBLIC: int __db_compact_pp __P((DB *, DB_TXN *, 1714 * PUBLIC: DBT *, DBT *, DB_COMPACT *, u_int32_t, DBT *)); 1715 */ 1716int 1717__db_compact_pp(dbp, txn, start, stop, c_data, flags, end) 1718 DB *dbp; 1719 DB_TXN *txn; 1720 DBT *start, *stop; 1721 DB_COMPACT *c_data; 1722 u_int32_t flags; 1723 DBT *end; 1724{ 1725 DB_COMPACT *dp, l_data; 1726 DB_THREAD_INFO *ip; 1727 ENV *env; 1728 int handle_check, ret, t_ret; 1729 1730 env = dbp->env; 1731 1732 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->compact"); 1733 1734 /* 1735 * !!! 1736 * The actual argument checking is simple, do it inline, outside of 1737 * the replication block. 1738 */ 1739 if ((ret = __db_fchk( 1740 env, "DB->compact", flags, DB_FREELIST_ONLY | DB_FREE_SPACE)) != 0) 1741 return (ret); 1742 1743 /* Check for changes to a read-only database. */ 1744 if (DB_IS_READONLY(dbp)) 1745 return (__db_rdonly(env, "DB->compact")); 1746 1747 if (start != NULL && (ret = __dbt_usercopy(env, start)) != 0) 1748 return (ret); 1749 if (stop != NULL && (ret = __dbt_usercopy(env, stop)) != 0) 1750 return (ret); 1751 1752 ENV_ENTER(env, ip); 1753 1754 /* Check for replication block. */ 1755 handle_check = IS_ENV_REPLICATED(env); 1756 if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 1757 txn != NULL)) != 0) { 1758 handle_check = 0; 1759 goto err; 1760 } 1761 1762 if (c_data == NULL) { 1763 dp = &l_data; 1764 memset(dp, 0, sizeof(*dp)); 1765 } else 1766 dp = c_data; 1767#ifdef HAVE_PARTITION 1768 if (DB_IS_PARTITIONED(dbp)) 1769 ret = __part_compact(dbp, ip, txn, start, stop, dp, flags, end); 1770 else 1771#endif 1772 switch (dbp->type) { 1773 case DB_HASH: 1774 if (!LF_ISSET(DB_FREELIST_ONLY)) 1775 goto err; 1776 /* FALLTHROUGH */ 1777 case DB_BTREE: 1778 case DB_RECNO: 1779 ret = __bam_compact(dbp, ip, txn, start, stop, dp, flags, end); 1780 break; 1781 1782 default: 1783err: ret = __dbh_am_chk(dbp, DB_OK_BTREE); 1784 break; 1785 } 1786 1787 /* Release replication block. */ 1788 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 1789 ret = t_ret; 1790 1791 ENV_LEAVE(env, ip); 1792 __dbt_userfree(env, start, stop, NULL); 1793 return (ret); 1794} 1795 1796/* 1797 * __db_associate_foreign_pp -- 1798 * DB->associate_foreign pre/post processing. 1799 * 1800 * PUBLIC: int __db_associate_foreign_pp __P((DB *, DB *, 1801 * PUBLIC: int (*)(DB *, const DBT *, DBT *, const DBT *, int *), 1802 * PUBLIC: u_int32_t)); 1803 */ 1804int 1805__db_associate_foreign_pp(fdbp, dbp, callback, flags) 1806 DB *dbp, *fdbp; 1807 int (*callback) __P((DB *, const DBT *, DBT *, const DBT *, int *)); 1808 u_int32_t flags; 1809{ 1810 /* Most of this is based on the implementation of associate */ 1811 DB_THREAD_INFO *ip; 1812 ENV *env; 1813 int handle_check, ret, t_ret; 1814 1815 env = dbp->env; 1816 1817 PANIC_CHECK(env); 1818 STRIP_AUTO_COMMIT(flags); 1819 1820 ENV_ENTER(env, ip); 1821 1822 /* Check for replication block. */ 1823 handle_check = IS_ENV_REPLICATED(env); 1824 if (handle_check && 1825 (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) { 1826 handle_check = 0; 1827 goto err; 1828 } 1829 1830 if ((ret = __db_associate_foreign_arg(fdbp, dbp, callback, flags)) != 0) 1831 goto err; 1832 1833 ret = __db_associate_foreign(fdbp, dbp, callback, flags); 1834 1835err: /* Release replication block. */ 1836 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 1837 ret = t_ret; 1838 ENV_LEAVE(env, ip); 1839 return (ret); 1840} 1841 1842/* 1843 * __db_associate_foreign_arg -- 1844 * DB->associate_foreign argument checking. 1845 */ 1846static int 1847__db_associate_foreign_arg(fdbp, dbp, callback, flags) 1848 DB *dbp, *fdbp; 1849 int (*callback) __P((DB *, const DBT *, DBT *, const DBT *, int *)); 1850 u_int32_t flags; 1851{ 1852 ENV *env; 1853 1854 env = fdbp->env; 1855 1856 if (F_ISSET(fdbp, DB_AM_SECONDARY)) { 1857 __db_errx(env, 1858 "Secondary indices may not be used as foreign databases"); 1859 return (EINVAL); 1860 } 1861 if (F_ISSET(fdbp, DB_AM_DUP)) { 1862 __db_errx(env, 1863 "Foreign databases may not be configured with duplicates"); 1864 return (EINVAL); 1865 } 1866 if (F_ISSET(fdbp, DB_AM_RENUMBER)) { 1867 __db_errx(env, 1868 "Renumbering recno databases may not be used as foreign databases"); 1869 return (EINVAL); 1870 } 1871 if (!F_ISSET(dbp, DB_AM_SECONDARY)) { 1872 __db_errx(env, 1873 "The associating database must be a secondary index."); 1874 return (EINVAL); 1875 } 1876 if (LF_ISSET(DB_FOREIGN_NULLIFY) && callback == NULL) { 1877 __db_errx(env, 1878 "When specifying a delete action of nullify, a callback%s", 1879 " function needs to be configured"); 1880 return (EINVAL); 1881 } else if (!LF_ISSET(DB_FOREIGN_NULLIFY) && callback != NULL) { 1882 __db_errx(env, 1883 "When not specifying a delete action of nullify, a%s", 1884 " callback function cannot be configured"); 1885 return (EINVAL); 1886 } 1887 1888 return (0); 1889} 1890 1891/* 1892 * __db_sync_pp -- 1893 * DB->sync pre/post processing. 1894 * 1895 * PUBLIC: int __db_sync_pp __P((DB *, u_int32_t)); 1896 */ 1897int 1898__db_sync_pp(dbp, flags) 1899 DB *dbp; 1900 u_int32_t flags; 1901{ 1902 DB_THREAD_INFO *ip; 1903 ENV *env; 1904 int handle_check, ret, t_ret; 1905 1906 env = dbp->env; 1907 1908 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync"); 1909 1910 /* 1911 * !!! 1912 * The actual argument checking is simple, do it inline, outside of 1913 * the replication block. 1914 */ 1915 if (flags != 0) 1916 return (__db_ferr(env, "DB->sync", 0)); 1917 1918 ENV_ENTER(env, ip); 1919 1920 /* Check for replication block. */ 1921 handle_check = IS_ENV_REPLICATED(env); 1922 if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) { 1923 handle_check = 0; 1924 goto err; 1925 } 1926 1927 ret = __db_sync(dbp); 1928 1929 /* Release replication block. */ 1930 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 1931 ret = t_ret; 1932 1933err: ENV_LEAVE(env, ip); 1934 return (ret); 1935} 1936 1937/* 1938 * __dbc_close_pp -- 1939 * DBC->close pre/post processing. 1940 * 1941 * PUBLIC: int __dbc_close_pp __P((DBC *)); 1942 */ 1943int 1944__dbc_close_pp(dbc) 1945 DBC *dbc; 1946{ 1947 DB *dbp; 1948 DB_THREAD_INFO *ip; 1949 ENV *env; 1950 int handle_check, ret, t_ret; 1951 1952 dbp = dbc->dbp; 1953 env = dbp->env; 1954 1955 /* 1956 * If the cursor is already closed we have a serious problem, and we 1957 * assume that the cursor isn't on the active queue. Don't do any of 1958 * the remaining cursor close processing. 1959 */ 1960 if (!F_ISSET(dbc, DBC_ACTIVE)) { 1961 __db_errx(env, "Closing already-closed cursor"); 1962 return (EINVAL); 1963 } 1964 1965 ENV_ENTER(env, ip); 1966 1967 /* Check for replication block. */ 1968 handle_check = dbc->txn == NULL && IS_ENV_REPLICATED(env); 1969 ret = __dbc_close(dbc); 1970 1971 /* Release replication block. */ 1972 if (handle_check && 1973 (t_ret = __op_rep_exit(env)) != 0 && ret == 0) 1974 ret = t_ret; 1975 1976 ENV_LEAVE(env, ip); 1977 return (ret); 1978} 1979 1980/* 1981 * __dbc_cmp_pp -- 1982 * DBC->cmp pre/post processing. 1983 * 1984 * PUBLIC: int __dbc_cmp_pp __P((DBC *, DBC *, int*, u_int32_t)); 1985 */ 1986int 1987__dbc_cmp_pp(dbc, other_cursor, result, flags) 1988 DBC *dbc, *other_cursor; 1989 int *result; 1990 u_int32_t flags; 1991{ 1992 DB *dbp, *odbp; 1993 DB_THREAD_INFO *ip; 1994 ENV *env; 1995 int ret; 1996 1997 dbp = dbc->dbp; 1998 odbp = other_cursor->dbp; 1999 env = dbp->env; 2000 2001 if (flags != 0) 2002 return (__db_ferr(env, "DBcursor->cmp", 0)); 2003 2004 if (other_cursor == NULL) { 2005 __db_errx(env, "DBcursor->cmp dbc pointer must not be null"); 2006 return (EINVAL); 2007 } 2008 2009 if (dbp != odbp) { 2010 __db_errx(env, 2011"DBcursor->cmp both cursors must refer to the same database."); 2012 return (EINVAL); 2013 } 2014 2015 ENV_ENTER(env, ip); 2016 ret = __dbc_cmp(dbc, other_cursor, result); 2017 ENV_LEAVE(env, ip); 2018 return (ret); 2019} 2020 2021/* 2022 * __dbc_count_pp -- 2023 * DBC->count pre/post processing. 2024 * 2025 * PUBLIC: int __dbc_count_pp __P((DBC *, db_recno_t *, u_int32_t)); 2026 */ 2027int 2028__dbc_count_pp(dbc, recnop, flags) 2029 DBC *dbc; 2030 db_recno_t *recnop; 2031 u_int32_t flags; 2032{ 2033 DB *dbp; 2034 DB_THREAD_INFO *ip; 2035 ENV *env; 2036 int ret; 2037 2038 dbp = dbc->dbp; 2039 env = dbp->env; 2040 2041 /* 2042 * !!! 2043 * The actual argument checking is simple, do it inline, outside of 2044 * the replication block. 2045 * 2046 * The cursor must be initialized, return EINVAL for an invalid cursor. 2047 */ 2048 if (flags != 0) 2049 return (__db_ferr(env, "DBcursor->count", 0)); 2050 2051 if (!IS_INITIALIZED(dbc)) 2052 return (__db_curinval(env)); 2053 2054 ENV_ENTER(env, ip); 2055 ret = __dbc_count(dbc, recnop); 2056 ENV_LEAVE(env, ip); 2057 return (ret); 2058} 2059 2060/* 2061 * __dbc_del_pp -- 2062 * DBC->del pre/post processing. 2063 * 2064 * PUBLIC: int __dbc_del_pp __P((DBC *, u_int32_t)); 2065 */ 2066int 2067__dbc_del_pp(dbc, flags) 2068 DBC *dbc; 2069 u_int32_t flags; 2070{ 2071 DB *dbp; 2072 DB_THREAD_INFO *ip; 2073 ENV *env; 2074 int ret; 2075 2076 dbp = dbc->dbp; 2077 env = dbp->env; 2078 2079 if ((ret = __dbc_del_arg(dbc, flags)) != 0) 2080 return (ret); 2081 2082 ENV_ENTER(env, ip); 2083 2084 /* Check for consistent transaction usage. */ 2085 if ((ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0) 2086 goto err; 2087 2088 DEBUG_LWRITE(dbc, dbc->txn, "DBcursor->del", NULL, NULL, flags); 2089 ret = __dbc_del(dbc, flags); 2090 2091err: ENV_LEAVE(env, ip); 2092 return (ret); 2093} 2094 2095/* 2096 * __dbc_del_arg -- 2097 * Check DBC->del arguments. 2098 */ 2099static int 2100__dbc_del_arg(dbc, flags) 2101 DBC *dbc; 2102 u_int32_t flags; 2103{ 2104 DB *dbp; 2105 ENV *env; 2106 2107 dbp = dbc->dbp; 2108 env = dbp->env; 2109 2110 /* Check for changes to a read-only tree. */ 2111 if (DB_IS_READONLY(dbp)) 2112 return (__db_rdonly(env, "DBcursor->del")); 2113 2114 /* Check for invalid function flags. */ 2115 switch (flags) { 2116 case 0: 2117 break; 2118 case DB_CONSUME: 2119 if (dbp->type != DB_QUEUE) 2120 return (__db_ferr(env, "DBC->del", 0)); 2121 break; 2122 case DB_UPDATE_SECONDARY: 2123 DB_ASSERT(env, F_ISSET(dbp, DB_AM_SECONDARY)); 2124 break; 2125 default: 2126 return (__db_ferr(env, "DBcursor->del", 0)); 2127 } 2128 2129 /* 2130 * The cursor must be initialized, return EINVAL for an invalid cursor, 2131 * otherwise 0. 2132 */ 2133 if (!IS_INITIALIZED(dbc)) 2134 return (__db_curinval(env)); 2135 2136 return (0); 2137} 2138 2139/* 2140 * __dbc_dup_pp -- 2141 * DBC->dup pre/post processing. 2142 * 2143 * PUBLIC: int __dbc_dup_pp __P((DBC *, DBC **, u_int32_t)); 2144 */ 2145int 2146__dbc_dup_pp(dbc, dbcp, flags) 2147 DBC *dbc, **dbcp; 2148 u_int32_t flags; 2149{ 2150 DB *dbp; 2151 DB_THREAD_INFO *ip; 2152 ENV *env; 2153 int ret; 2154 2155 dbp = dbc->dbp; 2156 env = dbp->env; 2157 2158 /* 2159 * !!! 2160 * The actual argument checking is simple, do it inline, outside of 2161 * the replication block. 2162 */ 2163 if (flags != 0 && flags != DB_POSITION) 2164 return (__db_ferr(env, "DBcursor->dup", 0)); 2165 2166 ENV_ENTER(env, ip); 2167 ret = __dbc_dup(dbc, dbcp, flags); 2168 ENV_LEAVE(env, ip); 2169 return (ret); 2170} 2171 2172/* 2173 * __dbc_get_pp -- 2174 * DBC->get pre/post processing. 2175 * 2176 * PUBLIC: int __dbc_get_pp __P((DBC *, DBT *, DBT *, u_int32_t)); 2177 */ 2178int 2179__dbc_get_pp(dbc, key, data, flags) 2180 DBC *dbc; 2181 DBT *key, *data; 2182 u_int32_t flags; 2183{ 2184 DB *dbp; 2185 DB_THREAD_INFO *ip; 2186 ENV *env; 2187 int ignore_lease, ret; 2188 2189 dbp = dbc->dbp; 2190 env = dbp->env; 2191 2192 ignore_lease = LF_ISSET(DB_IGNORE_LEASE) ? 1 : 0; 2193 LF_CLR(DB_IGNORE_LEASE); 2194 if ((ret = __dbc_get_arg(dbc, key, data, flags)) != 0) 2195 return (ret); 2196 2197 ENV_ENTER(env, ip); 2198 2199 DEBUG_LREAD(dbc, dbc->txn, "DBcursor->get", 2200 flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags); 2201 ret = __dbc_get(dbc, key, data, flags); 2202 2203 /* 2204 * Check for master leases. 2205 */ 2206 if (ret == 0 && 2207 IS_REP_MASTER(env) && IS_USING_LEASES(env) && !ignore_lease) 2208 ret = __rep_lease_check(env, 1); 2209 2210 ENV_LEAVE(env, ip); 2211 __dbt_userfree(env, key, NULL, data); 2212 return (ret); 2213} 2214 2215/* 2216 * __dbc_get_arg -- 2217 * Common DBC->get argument checking, used by both DBC->get and DBC->pget. 2218 * PUBLIC: int __dbc_get_arg __P((DBC *, DBT *, DBT *, u_int32_t)); 2219 */ 2220int 2221__dbc_get_arg(dbc, key, data, flags) 2222 DBC *dbc; 2223 DBT *key, *data; 2224 u_int32_t flags; 2225{ 2226 DB *dbp; 2227 ENV *env; 2228 int dirty, multi, ret; 2229 2230 dbp = dbc->dbp; 2231 env = dbp->env; 2232 2233 /* 2234 * Typically in checking routines that modify the flags, we have 2235 * to save them and restore them, because the checking routine 2236 * calls the work routine. However, this is a pure-checking 2237 * routine which returns to a function that calls the work routine, 2238 * so it's OK that we do not save and restore the flags, even though 2239 * we modify them. 2240 * 2241 * Check for read-modify-write validity. DB_RMW doesn't make sense 2242 * with CDB cursors since if you're going to write the cursor, you 2243 * had to create it with DB_WRITECURSOR. Regardless, we check for 2244 * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it. 2245 * If this changes, confirm that DB does not itself set the DB_RMW 2246 * flag in a path where CDB may have been configured. 2247 */ 2248 dirty = 0; 2249 if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW)) { 2250 if (!LOCKING_ON(env)) 2251 return (__db_fnl(env, "DBcursor->get")); 2252 if (LF_ISSET(DB_READ_UNCOMMITTED)) 2253 dirty = 1; 2254 LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW); 2255 } 2256 2257 multi = 0; 2258 if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) { 2259 multi = 1; 2260 if (LF_ISSET(DB_MULTIPLE) && LF_ISSET(DB_MULTIPLE_KEY)) 2261 goto multi_err; 2262 LF_CLR(DB_MULTIPLE | DB_MULTIPLE_KEY); 2263 } 2264 2265 /* Check for invalid function flags. */ 2266 switch (flags) { 2267 case DB_CONSUME: 2268 case DB_CONSUME_WAIT: 2269 if (dirty) { 2270 __db_errx(env, 2271 "DB_READ_UNCOMMITTED is not supported with DB_CONSUME or DB_CONSUME_WAIT"); 2272 return (EINVAL); 2273 } 2274 if (dbp->type != DB_QUEUE) 2275 goto err; 2276 break; 2277 case DB_CURRENT: 2278 case DB_FIRST: 2279 case DB_NEXT: 2280 case DB_NEXT_DUP: 2281 case DB_NEXT_NODUP: 2282 break; 2283 case DB_LAST: 2284 case DB_PREV: 2285 case DB_PREV_DUP: 2286 case DB_PREV_NODUP: 2287 if (multi) 2288multi_err: return (__db_ferr(env, "DBcursor->get", 1)); 2289 break; 2290 case DB_GET_BOTHC: 2291 if (dbp->type == DB_QUEUE) 2292 goto err; 2293 /* FALLTHROUGH */ 2294 case DB_GET_BOTH: 2295 case DB_GET_BOTH_RANGE: 2296 if ((ret = __dbt_usercopy(env, data)) != 0) 2297 goto err; 2298 /* FALLTHROUGH */ 2299 case DB_SET: 2300 case DB_SET_RANGE: 2301 if ((ret = __dbt_usercopy(env, key)) != 0) 2302 goto err; 2303 break; 2304 case DB_GET_RECNO: 2305 /* 2306 * The one situation in which this might be legal with a 2307 * non-RECNUM dbp is if dbp is a secondary and its primary is 2308 * DB_AM_RECNUM. 2309 */ 2310 if (!F_ISSET(dbp, DB_AM_RECNUM) && 2311 (!F_ISSET(dbp, DB_AM_SECONDARY) || 2312 !F_ISSET(dbp->s_primary, DB_AM_RECNUM))) 2313 goto err; 2314 break; 2315 case DB_SET_RECNO: 2316 if (!F_ISSET(dbp, DB_AM_RECNUM)) 2317 goto err; 2318 if ((ret = __dbt_usercopy(env, key)) != 0) 2319 goto err; 2320 break; 2321 default: 2322err: __dbt_userfree(env, key, NULL, data); 2323 return (__db_ferr(env, "DBcursor->get", 0)); 2324 } 2325 2326 /* Check for invalid key/data flags. */ 2327 if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0) 2328 return (ret); 2329 if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) 2330 return (ret); 2331 2332 if (multi) { 2333 if (!F_ISSET(data, DB_DBT_USERMEM)) { 2334 __db_errx(env, 2335 "DB_MULTIPLE/DB_MULTIPLE_KEY require DB_DBT_USERMEM be set"); 2336 return (EINVAL); 2337 } 2338 if (F_ISSET(key, DB_DBT_PARTIAL) || 2339 F_ISSET(data, DB_DBT_PARTIAL)) { 2340 __db_errx(env, 2341 "DB_MULTIPLE/DB_MULTIPLE_KEY do not support DB_DBT_PARTIAL"); 2342 return (EINVAL); 2343 } 2344 if (data->ulen < 1024 || 2345 data->ulen < dbp->pgsize || data->ulen % 1024 != 0) { 2346 __db_errx(env, "%s%s", 2347 "DB_MULTIPLE/DB_MULTIPLE_KEY buffers must be ", 2348 "aligned, at least page size and multiples of 1KB"); 2349 return (EINVAL); 2350 } 2351 } 2352 2353 /* 2354 * The cursor must be initialized for DB_CURRENT, DB_GET_RECNO, 2355 * DB_PREV_DUP and DB_NEXT_DUP. Return EINVAL for an invalid 2356 * cursor, otherwise 0. 2357 */ 2358 if (!IS_INITIALIZED(dbc) && (flags == DB_CURRENT || 2359 flags == DB_GET_RECNO || 2360 flags == DB_NEXT_DUP || flags == DB_PREV_DUP)) 2361 return (__db_curinval(env)); 2362 2363 /* Check for consistent transaction usage. */ 2364 if (LF_ISSET(DB_RMW) && 2365 (ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0) 2366 return (ret); 2367 2368 return (0); 2369} 2370 2371/* 2372 * __db_secondary_close_pp -- 2373 * DB->close for secondaries 2374 * 2375 * PUBLIC: int __db_secondary_close_pp __P((DB *, u_int32_t)); 2376 */ 2377int 2378__db_secondary_close_pp(dbp, flags) 2379 DB *dbp; 2380 u_int32_t flags; 2381{ 2382 DB_THREAD_INFO *ip; 2383 ENV *env; 2384 int handle_check, ret, t_ret; 2385 2386 env = dbp->env; 2387 ret = 0; 2388 2389 /* 2390 * As a DB handle destructor, we can't fail. 2391 * 2392 * !!! 2393 * The actual argument checking is simple, do it inline, outside of 2394 * the replication block. 2395 */ 2396 if (flags != 0 && flags != DB_NOSYNC) 2397 ret = __db_ferr(env, "DB->close", 0); 2398 2399 ENV_ENTER(env, ip); 2400 2401 /* Check for replication block. */ 2402 handle_check = IS_ENV_REPLICATED(env); 2403 if (handle_check && (t_ret = __db_rep_enter(dbp, 0, 0, 0)) != 0) { 2404 handle_check = 0; 2405 if (ret == 0) 2406 ret = t_ret; 2407 } 2408 2409 if ((t_ret = __db_secondary_close(dbp, flags)) != 0 && ret == 0) 2410 ret = t_ret; 2411 2412 /* Release replication block. */ 2413 if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0) 2414 ret = t_ret; 2415 2416 ENV_LEAVE(env, ip); 2417 return (ret); 2418} 2419 2420/* 2421 * __dbc_pget_pp -- 2422 * DBC->pget pre/post processing. 2423 * 2424 * PUBLIC: int __dbc_pget_pp __P((DBC *, DBT *, DBT *, DBT *, u_int32_t)); 2425 */ 2426int 2427__dbc_pget_pp(dbc, skey, pkey, data, flags) 2428 DBC *dbc; 2429 DBT *skey, *pkey, *data; 2430 u_int32_t flags; 2431{ 2432 DB *dbp; 2433 DB_THREAD_INFO *ip; 2434 ENV *env; 2435 int ignore_lease, ret; 2436 2437 dbp = dbc->dbp; 2438 env = dbp->env; 2439 2440 ignore_lease = LF_ISSET(DB_IGNORE_LEASE) ? 1 : 0; 2441 LF_CLR(DB_IGNORE_LEASE); 2442 if ((ret = __dbc_pget_arg(dbc, pkey, flags)) != 0 || 2443 (ret = __dbc_get_arg(dbc, skey, data, flags)) != 0) 2444 return (ret); 2445 2446 ENV_ENTER(env, ip); 2447 ret = __dbc_pget(dbc, skey, pkey, data, flags); 2448 /* 2449 * Check for master leases. 2450 */ 2451 if (ret == 0 && 2452 IS_REP_MASTER(env) && IS_USING_LEASES(env) && !ignore_lease) 2453 ret = __rep_lease_check(env, 1); 2454 2455 ENV_LEAVE(env, ip); 2456 2457 __dbt_userfree(env, skey, pkey, data); 2458 return (ret); 2459} 2460 2461/* 2462 * __dbc_pget_arg -- 2463 * Check DBC->pget arguments. 2464 */ 2465static int 2466__dbc_pget_arg(dbc, pkey, flags) 2467 DBC *dbc; 2468 DBT *pkey; 2469 u_int32_t flags; 2470{ 2471 DB *dbp; 2472 ENV *env; 2473 int ret; 2474 2475 dbp = dbc->dbp; 2476 env = dbp->env; 2477 2478 if (!F_ISSET(dbp, DB_AM_SECONDARY)) { 2479 __db_errx(env, 2480 "DBcursor->pget may only be used on secondary indices"); 2481 return (EINVAL); 2482 } 2483 2484 if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) { 2485 __db_errx(env, 2486 "DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices"); 2487 return (EINVAL); 2488 } 2489 2490 switch (LF_ISSET(DB_OPFLAGS_MASK)) { 2491 case DB_CONSUME: 2492 case DB_CONSUME_WAIT: 2493 /* These flags make no sense on a secondary index. */ 2494 return (__db_ferr(env, "DBcursor->pget", 0)); 2495 case DB_GET_BOTH: 2496 case DB_GET_BOTH_RANGE: 2497 /* BOTH is "get both the primary and the secondary". */ 2498 if (pkey == NULL) { 2499 __db_errx(env, 2500 "%s requires both a secondary and a primary key", 2501 LF_ISSET(DB_GET_BOTH) ? 2502 "DB_GET_BOTH" : "DB_GET_BOTH_RANGE"); 2503 return (EINVAL); 2504 } 2505 if ((ret = __dbt_usercopy(env, pkey)) != 0) 2506 return (ret); 2507 break; 2508 default: 2509 /* __dbc_get_arg will catch the rest. */ 2510 break; 2511 } 2512 2513 /* 2514 * We allow the pkey field to be NULL, so that we can make the 2515 * two-DBT get calls into wrappers for the three-DBT ones. 2516 */ 2517 if (pkey != NULL && 2518 (ret = __dbt_ferr(dbp, "primary key", pkey, 0)) != 0) 2519 return (ret); 2520 2521 /* But the pkey field can't be NULL if we're doing a DB_GET_BOTH. */ 2522 if (pkey == NULL && (flags & DB_OPFLAGS_MASK) == DB_GET_BOTH) { 2523 __db_errx(env, 2524 "DB_GET_BOTH on a secondary index requires a primary key"); 2525 return (EINVAL); 2526 } 2527 return (0); 2528} 2529 2530/* 2531 * __dbc_put_pp -- 2532 * DBC->put pre/post processing. 2533 * 2534 * PUBLIC: int __dbc_put_pp __P((DBC *, DBT *, DBT *, u_int32_t)); 2535 */ 2536int 2537__dbc_put_pp(dbc, key, data, flags) 2538 DBC *dbc; 2539 DBT *key, *data; 2540 u_int32_t flags; 2541{ 2542 DB *dbp; 2543 DB_THREAD_INFO *ip; 2544 ENV *env; 2545 int ret; 2546 2547 dbp = dbc->dbp; 2548 env = dbp->env; 2549 2550 if ((ret = __dbc_put_arg(dbc, key, data, flags)) != 0) 2551 return (ret); 2552 2553 ENV_ENTER(env, ip); 2554 2555 /* Check for consistent transaction usage. */ 2556 if ((ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0) 2557 goto err; 2558 2559 DEBUG_LWRITE(dbc, dbc->txn, "DBcursor->put", 2560 flags == DB_KEYFIRST || flags == DB_KEYLAST || 2561 flags == DB_NODUPDATA || flags == DB_UPDATE_SECONDARY ? 2562 key : NULL, data, flags); 2563 ret = __dbc_put(dbc, key, data, flags); 2564 2565err: ENV_LEAVE(env, ip); 2566 __dbt_userfree(env, key, NULL, data); 2567 return (ret); 2568} 2569 2570/* 2571 * __dbc_put_arg -- 2572 * Check DBC->put arguments. 2573 */ 2574static int 2575__dbc_put_arg(dbc, key, data, flags) 2576 DBC *dbc; 2577 DBT *key, *data; 2578 u_int32_t flags; 2579{ 2580 DB *dbp; 2581 ENV *env; 2582 int key_flags, ret; 2583 2584 dbp = dbc->dbp; 2585 env = dbp->env; 2586 key_flags = 0; 2587 2588 /* Check for changes to a read-only tree. */ 2589 if (DB_IS_READONLY(dbp)) 2590 return (__db_rdonly(env, "DBcursor->put")); 2591 2592 /* Check for puts on a secondary. */ 2593 if (F_ISSET(dbp, DB_AM_SECONDARY)) { 2594 if (flags == DB_UPDATE_SECONDARY) 2595 flags = 0; 2596 else { 2597 __db_errx(env, 2598 "DBcursor->put forbidden on secondary indices"); 2599 return (EINVAL); 2600 } 2601 } 2602 2603 if ((ret = __dbt_usercopy(env, data)) != 0) 2604 return (ret); 2605 2606 /* Check for invalid function flags. */ 2607 switch (flags) { 2608 case DB_AFTER: 2609 case DB_BEFORE: 2610 switch (dbp->type) { 2611 case DB_BTREE: 2612 case DB_HASH: /* Only with unsorted duplicates. */ 2613 if (!F_ISSET(dbp, DB_AM_DUP)) 2614 goto err; 2615 if (dbp->dup_compare != NULL) 2616 goto err; 2617 break; 2618 case DB_QUEUE: /* Not permitted. */ 2619 goto err; 2620 case DB_RECNO: /* Only with mutable record numbers. */ 2621 if (!F_ISSET(dbp, DB_AM_RENUMBER)) 2622 goto err; 2623 key_flags = key == NULL ? 0 : 1; 2624 break; 2625 case DB_UNKNOWN: 2626 default: 2627 goto err; 2628 } 2629 break; 2630 case DB_CURRENT: 2631 /* 2632 * If there is a comparison function, doing a DB_CURRENT 2633 * must not change the part of the data item that is used 2634 * for the comparison. 2635 */ 2636 break; 2637 case DB_NODUPDATA: 2638 if (!F_ISSET(dbp, DB_AM_DUPSORT)) 2639 goto err; 2640 /* FALLTHROUGH */ 2641 case DB_KEYFIRST: 2642 case DB_KEYLAST: 2643 case DB_OVERWRITE_DUP: 2644 key_flags = 1; 2645 if ((ret = __dbt_usercopy(env, key)) != 0) 2646 return (ret); 2647 break; 2648 default: 2649err: return (__db_ferr(env, "DBcursor->put", 0)); 2650 } 2651 2652 /* 2653 * Check for invalid key/data flags. The key may reasonably be NULL 2654 * if DB_AFTER or DB_BEFORE is set and the application doesn't care 2655 * about the returned key, or if the DB_CURRENT flag is set. 2656 */ 2657 if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0) 2658 return (ret); 2659 if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) 2660 return (ret); 2661 2662 /* 2663 * The key parameter should not be NULL or have the "partial" flag set 2664 * in a put call unless the user doesn't care about a key value we'd 2665 * return. The user tells us they don't care about the returned key by 2666 * setting the key parameter to NULL or configuring the key DBT to not 2667 * return any information. (Returned keys from a put are always record 2668 * numbers, and returning part of a record number doesn't make sense: 2669 * only accept a partial return if the length returned is 0.) 2670 */ 2671 if (key_flags && F_ISSET(key, DB_DBT_PARTIAL) && key->dlen != 0) 2672 return (__db_ferr(env, "key DBT", 0)); 2673 2674 /* 2675 * The cursor must be initialized for anything other than DB_KEYFIRST, 2676 * DB_KEYLAST or zero: return EINVAL for an invalid cursor, otherwise 0. 2677 */ 2678 if (!IS_INITIALIZED(dbc) && flags != 0 && flags != DB_KEYFIRST && 2679 flags != DB_KEYLAST && flags != DB_NODUPDATA && 2680 flags != DB_OVERWRITE_DUP) 2681 return (__db_curinval(env)); 2682 2683 return (0); 2684} 2685 2686/* 2687 * __dbt_ferr -- 2688 * Check a DBT for flag errors. 2689 */ 2690static int 2691__dbt_ferr(dbp, name, dbt, check_thread) 2692 const DB *dbp; 2693 const char *name; 2694 const DBT *dbt; 2695 int check_thread; 2696{ 2697 ENV *env; 2698 int ret; 2699 2700 env = dbp->env; 2701 2702 /* 2703 * Check for invalid DBT flags. We allow any of the flags to be 2704 * specified to any DB or DBcursor call so that applications can 2705 * set DB_DBT_MALLOC when retrieving a data item from a secondary 2706 * database and then specify that same DBT as a key to a primary 2707 * database, without having to clear flags. 2708 */ 2709 if ((ret = __db_fchk(env, name, dbt->flags, DB_DBT_APPMALLOC | 2710 DB_DBT_BULK | DB_DBT_DUPOK | DB_DBT_MALLOC | DB_DBT_REALLOC | 2711 DB_DBT_USERCOPY | DB_DBT_USERMEM | DB_DBT_PARTIAL)) != 0) 2712 return (ret); 2713 switch (F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | 2714 DB_DBT_USERCOPY | DB_DBT_USERMEM)) { 2715 case 0: 2716 case DB_DBT_MALLOC: 2717 case DB_DBT_REALLOC: 2718 case DB_DBT_USERCOPY: 2719 case DB_DBT_USERMEM: 2720 break; 2721 default: 2722 return (__db_ferr(env, name, 1)); 2723 } 2724 2725 if (F_ISSET(dbt, DB_DBT_BULK) && F_ISSET(dbt, DB_DBT_PARTIAL)) { 2726 __db_errx(env, 2727 "Bulk and partial operations cannot be combined on %s DBT", name); 2728 return (EINVAL); 2729 } 2730 2731 if (check_thread && DB_IS_THREADED(dbp) && 2732 !F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | 2733 DB_DBT_USERCOPY | DB_DBT_USERMEM)) { 2734 __db_errx(env, 2735 "DB_THREAD mandates memory allocation flag on %s DBT", 2736 name); 2737 return (EINVAL); 2738 } 2739 return (0); 2740} 2741 2742/* 2743 * __db_curinval 2744 * Report that a cursor is in an invalid state. 2745 */ 2746static int 2747__db_curinval(env) 2748 const ENV *env; 2749{ 2750 __db_errx(env, 2751 "Cursor position must be set before performing this operation"); 2752 return (EINVAL); 2753} 2754 2755/* 2756 * __db_txn_auto_init -- 2757 * Handle DB_AUTO_COMMIT initialization. 2758 * 2759 * PUBLIC: int __db_txn_auto_init __P((ENV *, DB_THREAD_INFO *, DB_TXN **)); 2760 */ 2761int 2762__db_txn_auto_init(env, ip, txnidp) 2763 ENV *env; 2764 DB_THREAD_INFO *ip; 2765 DB_TXN **txnidp; 2766{ 2767 /* 2768 * Method calls where applications explicitly specify DB_AUTO_COMMIT 2769 * require additional validation: the DB_AUTO_COMMIT flag cannot be 2770 * specified if a transaction cookie is also specified, nor can the 2771 * flag be specified in a non-transactional environment. 2772 */ 2773 if (*txnidp != NULL) { 2774 __db_errx(env, 2775 "DB_AUTO_COMMIT may not be specified along with a transaction handle"); 2776 return (EINVAL); 2777 } 2778 2779 if (!TXN_ON(env)) { 2780 __db_errx(env, 2781 "DB_AUTO_COMMIT may not be specified in non-transactional environment"); 2782 return (EINVAL); 2783 } 2784 2785 /* 2786 * Our caller checked to see if replication is making a state change. 2787 * Don't call the user-level API (which would repeat that check). 2788 */ 2789 return (__txn_begin(env, ip, NULL, txnidp, 0)); 2790} 2791 2792/* 2793 * __db_txn_auto_resolve -- 2794 * Resolve local transactions. 2795 * 2796 * PUBLIC: int __db_txn_auto_resolve __P((ENV *, DB_TXN *, int, int)); 2797 */ 2798int 2799__db_txn_auto_resolve(env, txn, nosync, ret) 2800 ENV *env; 2801 DB_TXN *txn; 2802 int nosync, ret; 2803{ 2804 int t_ret; 2805 2806 /* 2807 * We're resolving a transaction for the user, and must decrement the 2808 * replication handle count. Call the user-level API. 2809 */ 2810 if (ret == 0) 2811 return (__txn_commit(txn, nosync ? DB_TXN_NOSYNC : 0)); 2812 2813 if ((t_ret = __txn_abort(txn)) != 0) 2814 return (__env_panic(env, t_ret)); 2815 2816 return (ret); 2817} 2818