Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_iface.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_iface.c,v 12.29 2005/11/08 14:49:44 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/db_page.h"
00020 #include "dbinc/db_shash.h"
00021 #include "dbinc/btree.h"
00022 #ifndef HAVE_HASH
00023 #include "dbinc/hash.h"                 /* For __db_no_hash_am(). */
00024 #endif
00025 #ifndef HAVE_QUEUE
00026 #include "dbinc/qam.h"                  /* For __db_no_queue_am(). */
00027 #endif
00028 #include "dbinc/lock.h"
00029 #include "dbinc/log.h"
00030 #include "dbinc/mp.h"
00031 #include "dbinc/txn.h"
00032 
00033 static int __db_associate_arg __P((DB *, DB *,
00034                int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t));
00035 static int __db_c_del_arg __P((DBC *, u_int32_t));
00036 static int __db_c_get_arg __P((DBC *, DBT *, DBT *, u_int32_t));
00037 static int __db_c_pget_arg __P((DBC *, DBT *, u_int32_t));
00038 static int __db_c_put_arg __P((DBC *, DBT *, DBT *, u_int32_t));
00039 static int __db_curinval __P((const DB_ENV *));
00040 static int __db_cursor_arg __P((DB *, u_int32_t));
00041 static int __db_del_arg __P((DB *, u_int32_t));
00042 static int __db_get_arg __P((const DB *, const DBT *, DBT *, u_int32_t));
00043 static int __db_join_arg __P((DB *, DBC **, u_int32_t));
00044 static int __db_open_arg __P((DB *,
00045                DB_TXN *, const char *, const char *, DBTYPE, u_int32_t));
00046 static int __db_pget_arg __P((DB *, DBT *, u_int32_t));
00047 static int __db_put_arg __P((DB *, DBT *, DBT *, u_int32_t));
00048 static int __dbt_ferr __P((const DB *, const char *, const DBT *, int));
00049 
00050 /*
00051  * These functions implement the Berkeley DB API.  They are organized in a
00052  * layered fashion.  The interface functions (XXX_pp) perform all generic
00053  * error checks (for example, PANIC'd region, replication state change
00054  * in progress, inconsistent transaction usage), call function-specific
00055  * check routines (_arg) to check for proper flag usage, etc., do pre-amble
00056  * processing (incrementing handle counts, handling local transactions),
00057  * call the function and then do post-amble processing (local transactions,
00058  * decrement handle counts).
00059  *
00060  * The basic structure is:
00061  *      Check for simple/generic errors (PANIC'd region)
00062  *      Check if replication is changing state (increment handle count).
00063  *      Call function-specific argument checking routine
00064  *      Create internal transaction if necessary
00065  *      Call underlying worker function
00066  *      Commit/abort internal transaction if necessary
00067  *      Decrement handle count
00068  */
00069 
00070 /*
00071  * __db_associate_pp --
00072  *      DB->associate pre/post processing.
00073  *
00074  * PUBLIC: int __db_associate_pp __P((DB *, DB_TXN *, DB *,
00075  * PUBLIC:     int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t));
00076  */
00077 int
00078 __db_associate_pp(dbp, txn, sdbp, callback, flags)
00079         DB *dbp, *sdbp;
00080         DB_TXN *txn;
00081         int (*callback) __P((DB *, const DBT *, const DBT *, DBT *));
00082         u_int32_t flags;
00083 {
00084         DBC *sdbc;
00085         DB_ENV *dbenv;
00086         DB_THREAD_INFO *ip;
00087         int handle_check, ret, t_ret, txn_local;
00088 
00089         dbenv = dbp->dbenv;
00090         txn_local = 0;
00091 
00092         PANIC_CHECK(dbenv);
00093         STRIP_AUTO_COMMIT(flags);
00094 
00095         ENV_ENTER(dbenv, ip);
00096 
00097         /* Check for replication block. */
00098         handle_check = IS_ENV_REPLICATED(dbenv);
00099         if (handle_check &&
00100             (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
00101                 handle_check = 0;
00102                 goto err;
00103         }
00104 
00105         /*
00106          * Secondary cursors may have the primary's lock file ID, so we need
00107          * to make sure that no older cursors are lying around when we make
00108          * the transition.
00109          */
00110         if (TAILQ_FIRST(&sdbp->active_queue) != NULL ||
00111             TAILQ_FIRST(&sdbp->join_queue) != NULL) {
00112                 __db_err(dbenv,
00113     "Databases may not become secondary indices while cursors are open");
00114                 ret = EINVAL;
00115                 goto err;
00116         }
00117 
00118         if ((ret = __db_associate_arg(dbp, sdbp, callback, flags)) != 0)
00119                 goto err;
00120 
00121         /*
00122          * Create a local transaction as necessary, check for consistent
00123          * transaction usage, and, if we have no transaction but do have
00124          * locking on, acquire a locker id for the handle lock acquisition.
00125          */
00126         if (IS_DB_AUTO_COMMIT(dbp, txn)) {
00127                 if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0)
00128                         goto err;
00129                 txn_local = 1;
00130         }
00131 
00132         /* Check for consistent transaction usage. */
00133         if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
00134                 goto err;
00135 
00136         while ((sdbc = TAILQ_FIRST(&sdbp->free_queue)) != NULL)
00137                 if ((ret = __db_c_destroy(sdbc)) != 0)
00138                         goto err;
00139 
00140         ret = __db_associate(dbp, txn, sdbp, callback, flags);
00141 
00142 err:    if (txn_local &&
00143             (t_ret = __db_txn_auto_resolve(dbenv, txn, 0, ret)) && ret == 0)
00144                 ret = t_ret;
00145 
00146         /* Release replication block. */
00147         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00148                 ret = t_ret;
00149         ENV_LEAVE(dbenv, ip);
00150         return (ret);
00151 }
00152 
00153 /*
00154  * __db_associate_arg --
00155  *      Check DB->associate arguments.
00156  */
00157 static int
00158 __db_associate_arg(dbp, sdbp, callback, flags)
00159         DB *dbp, *sdbp;
00160         int (*callback) __P((DB *, const DBT *, const DBT *, DBT *));
00161         u_int32_t flags;
00162 {
00163         DB_ENV *dbenv;
00164         int ret;
00165 
00166         dbenv = dbp->dbenv;
00167 
00168         if (F_ISSET(sdbp, DB_AM_SECONDARY)) {
00169                 __db_err(dbenv,
00170                     "Secondary index handles may not be re-associated");
00171                 return (EINVAL);
00172         }
00173         if (F_ISSET(dbp, DB_AM_SECONDARY)) {
00174                 __db_err(dbenv,
00175                     "Secondary indices may not be used as primary databases");
00176                 return (EINVAL);
00177         }
00178         if (F_ISSET(dbp, DB_AM_DUP)) {
00179                 __db_err(dbenv,
00180                     "Primary databases may not be configured with duplicates");
00181                 return (EINVAL);
00182         }
00183         if (F_ISSET(dbp, DB_AM_RENUMBER)) {
00184                 __db_err(dbenv,
00185             "Renumbering recno databases may not be used as primary databases");
00186                 return (EINVAL);
00187         }
00188         if (dbp->dbenv != sdbp->dbenv &&
00189             (!F_ISSET(dbp->dbenv, DB_ENV_DBLOCAL) ||
00190              !F_ISSET(sdbp->dbenv, DB_ENV_DBLOCAL))) {
00191                 __db_err(dbenv,
00192             "The primary and secondary must be opened in the same environment");
00193                 return (EINVAL);
00194         }
00195         if ((DB_IS_THREADED(dbp) && !DB_IS_THREADED(sdbp)) ||
00196             (!DB_IS_THREADED(dbp) && DB_IS_THREADED(sdbp))) {
00197                 __db_err(dbenv,
00198             "The DB_THREAD setting must be the same for primary and secondary");
00199                 return (EINVAL);
00200         }
00201         if (callback == NULL &&
00202             (!F_ISSET(dbp, DB_AM_RDONLY) || !F_ISSET(sdbp, DB_AM_RDONLY))) {
00203                 __db_err(dbenv,
00204     "Callback function may be NULL only when database handles are read-only");
00205                 return (EINVAL);
00206         }
00207 
00208         if ((ret = __db_fchk(dbenv, "DB->associate", flags, DB_CREATE |
00209             DB_IMMUTABLE_KEY)) != 0)
00210                 return (ret);
00211 
00212         return (0);
00213 }
00214 
00215 /*
00216  * __db_close_pp --
00217  *      DB->close pre/post processing.
00218  *
00219  * PUBLIC: int __db_close_pp __P((DB *, u_int32_t));
00220  */
00221 int
00222 __db_close_pp(dbp, flags)
00223         DB *dbp;
00224         u_int32_t flags;
00225 {
00226         DB_ENV *dbenv;
00227         DB_THREAD_INFO *ip;
00228         int handle_check, ret, t_ret;
00229 
00230         dbenv = dbp->dbenv;
00231         ret = 0;
00232 
00233         PANIC_CHECK(dbenv);
00234 
00235         /*
00236          * Close a DB handle -- as a handle destructor, we can't fail.
00237          *
00238          * !!!
00239          * The actual argument checking is simple, do it inline, outside of
00240          * the replication block.
00241          */
00242         if (flags != 0 && flags != DB_NOSYNC)
00243                 ret = __db_ferr(dbenv, "DB->close", 0);
00244 
00245         ENV_ENTER(dbenv, ip);
00246 
00247         /* Check for replication block. */
00248         handle_check = IS_ENV_REPLICATED(dbenv);
00249         if (handle_check && (t_ret = __db_rep_enter(dbp, 0, 0, 0)) != 0) {
00250                 handle_check = 0;
00251                 if (ret == 0)
00252                         ret = t_ret;
00253         }
00254 
00255         if ((t_ret = __db_close(dbp, NULL, flags)) != 0 && ret == 0)
00256                 ret = t_ret;
00257 
00258         /* Release replication block. */
00259         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00260                 ret = t_ret;
00261 
00262         ENV_LEAVE(dbenv, ip);
00263         return (ret);
00264 }
00265 
00266 /*
00267  * __db_cursor_pp --
00268  *      DB->cursor pre/post processing.
00269  *
00270  * PUBLIC: int __db_cursor_pp __P((DB *, DB_TXN *, DBC **, u_int32_t));
00271  */
00272 int
00273 __db_cursor_pp(dbp, txn, dbcp, flags)
00274         DB *dbp;
00275         DB_TXN *txn;
00276         DBC **dbcp;
00277         u_int32_t flags;
00278 {
00279         DB_ENV *dbenv;
00280         DB_THREAD_INFO *ip;
00281         int handle_check, ret;
00282 
00283         dbenv = dbp->dbenv;
00284 
00285         PANIC_CHECK(dbenv);
00286         DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->cursor");
00287 
00288         ENV_ENTER(dbenv, ip);
00289 
00290         /* Check for replication block. */
00291         if (txn == NULL) {
00292                 handle_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0;
00293                 if (handle_check && (ret = __op_rep_enter(dbenv)) != 0) {
00294                         handle_check = 0;
00295                         goto err;
00296                 }
00297         } else
00298                 handle_check = 0;
00299         if ((ret = __db_cursor_arg(dbp, flags)) != 0)
00300                 goto err;
00301 
00302         /*
00303          * Check for consistent transaction usage.  For now, assume this
00304          * cursor might be used for read operations only (in which case
00305          * it may not require a txn).  We'll check more stringently in
00306          * c_del and c_put.  (Note this means the read-op txn tests have
00307          * to be a subset of the write-op ones.)
00308          */
00309         if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0)
00310                 goto err;
00311 
00312         ret = __db_cursor(dbp, txn, dbcp, flags);
00313 
00314 err:    /* Release replication block on error. */
00315         if (ret != 0 && handle_check)
00316                 (void)__op_rep_exit(dbenv);
00317 
00318         ENV_LEAVE(dbenv, ip);
00319         return (ret);
00320 }
00321 
00322 /*
00323  * __db_cursor --
00324  *      DB->cursor.
00325  *
00326  * PUBLIC: int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t));
00327  */
00328 int
00329 __db_cursor(dbp, txn, dbcp, flags)
00330         DB *dbp;
00331         DB_TXN *txn;
00332         DBC **dbcp;
00333         u_int32_t flags;
00334 {
00335         DB_ENV *dbenv;
00336         DBC *dbc;
00337         db_lockmode_t mode;
00338         u_int32_t op;
00339         int ret;
00340 
00341         dbenv = dbp->dbenv;
00342 
00343         if ((ret = __db_cursor_int(dbp,
00344             txn, dbp->type, PGNO_INVALID, 0, DB_LOCK_INVALIDID, &dbc)) != 0)
00345                 return (ret);
00346 
00347         /*
00348          * If this is CDB, do all the locking in the interface, which is
00349          * right here.
00350          */
00351         if (CDB_LOCKING(dbenv)) {
00352                 op = LF_ISSET(DB_OPFLAGS_MASK);
00353                 mode = (op == DB_WRITELOCK) ? DB_LOCK_WRITE :
00354                     ((op == DB_WRITECURSOR) ? DB_LOCK_IWRITE : DB_LOCK_READ);
00355                 if ((ret = __lock_get(dbenv, dbc->locker, 0,
00356                     &dbc->lock_dbt, mode, &dbc->mylock)) != 0)
00357                         goto err;
00358                 if (op == DB_WRITECURSOR)
00359                         F_SET(dbc, DBC_WRITECURSOR);
00360                 if (op == DB_WRITELOCK)
00361                         F_SET(dbc, DBC_WRITER);
00362         }
00363 
00364         if (LF_ISSET(DB_READ_UNCOMMITTED) ||
00365             (txn != NULL && F_ISSET(txn, TXN_READ_UNCOMMITTED)))
00366                 F_SET(dbc, DBC_READ_UNCOMMITTED);
00367 
00368         if (LF_ISSET(DB_READ_COMMITTED) ||
00369             (txn != NULL && F_ISSET(txn, TXN_READ_COMMITTED)))
00370                 F_SET(dbc, DBC_READ_COMMITTED);
00371 
00372         *dbcp = dbc;
00373         return (0);
00374 
00375 err:    (void)__db_c_close(dbc);
00376         return (ret);
00377 }
00378 
00379 /*
00380  * __db_cursor_arg --
00381  *      Check DB->cursor arguments.
00382  */
00383 static int
00384 __db_cursor_arg(dbp, flags)
00385         DB *dbp;
00386         u_int32_t flags;
00387 {
00388         DB_ENV *dbenv;
00389 
00390         dbenv = dbp->dbenv;
00391 
00392         /*
00393          * DB_READ_COMMITTED and DB_READ_UNCOMMITTED are the only valid
00394          * bit-flags; they require locking.
00395          */
00396         if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED)) {
00397                 if (!LOCKING_ON(dbenv))
00398                         return (__db_fnl(dbenv, "DB->cursor"));
00399                 LF_CLR(DB_READ_COMMITTED| DB_READ_UNCOMMITTED);
00400         }
00401 
00402         /* Check for invalid function flags. */
00403         switch (flags) {
00404         case 0:
00405                 break;
00406         case DB_WRITECURSOR:
00407                 if (DB_IS_READONLY(dbp))
00408                         return (__db_rdonly(dbenv, "DB->cursor"));
00409                 if (!CDB_LOCKING(dbenv))
00410                         return (__db_ferr(dbenv, "DB->cursor", 0));
00411                 break;
00412         case DB_WRITELOCK:
00413                 if (DB_IS_READONLY(dbp))
00414                         return (__db_rdonly(dbenv, "DB->cursor"));
00415                 break;
00416         default:
00417                 return (__db_ferr(dbenv, "DB->cursor", 0));
00418         }
00419 
00420         return (0);
00421 }
00422 
00423 /*
00424  * __db_del_pp --
00425  *      DB->del pre/post processing.
00426  *
00427  * PUBLIC: int __db_del_pp __P((DB *, DB_TXN *, DBT *, u_int32_t));
00428  */
00429 int
00430 __db_del_pp(dbp, txn, key, flags)
00431         DB *dbp;
00432         DB_TXN *txn;
00433         DBT *key;
00434         u_int32_t flags;
00435 {
00436         DB_ENV *dbenv;
00437         DB_THREAD_INFO *ip;
00438         int handle_check, ret, t_ret, txn_local;
00439 
00440         dbenv = dbp->dbenv;
00441         txn_local = 0;
00442 
00443         PANIC_CHECK(dbenv);
00444         STRIP_AUTO_COMMIT(flags);
00445         DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->del");
00446 
00447 #if CONFIG_TEST
00448         if (IS_REP_MASTER(dbenv))
00449                 DB_TEST_WAIT(dbenv, dbenv->test_check);
00450 #endif
00451         ENV_ENTER(dbenv, ip);
00452 
00453         /* Check for replication block. */
00454         handle_check = IS_ENV_REPLICATED(dbenv);
00455         if (handle_check &&
00456              (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
00457                         handle_check = 0;
00458                         goto err;
00459         }
00460 
00461         if ((ret = __db_del_arg(dbp, flags)) != 0)
00462                 goto err;
00463 
00464         /* Create local transaction as necessary. */
00465         if (IS_DB_AUTO_COMMIT(dbp, txn)) {
00466                 if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0)
00467                         goto err;
00468                 txn_local = 1;
00469         }
00470 
00471         /* Check for consistent transaction usage. */
00472         if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
00473                 goto err;
00474 
00475         ret = __db_del(dbp, txn, key, flags);
00476 
00477 err:    if (txn_local &&
00478             (t_ret = __db_txn_auto_resolve(dbenv, txn, 0, ret)) && ret == 0)
00479                 ret = t_ret;
00480 
00481         /* Release replication block. */
00482         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00483                 ret = t_ret;
00484         ENV_LEAVE(dbenv, ip);
00485         return (ret);
00486 }
00487 
00488 /*
00489  * __db_del_arg --
00490  *      Check DB->delete arguments.
00491  */
00492 static int
00493 __db_del_arg(dbp, flags)
00494         DB *dbp;
00495         u_int32_t flags;
00496 {
00497         DB_ENV *dbenv;
00498 
00499         dbenv = dbp->dbenv;
00500 
00501         /* Check for changes to a read-only tree. */
00502         if (DB_IS_READONLY(dbp))
00503                 return (__db_rdonly(dbenv, "DB->del"));
00504 
00505         /* Check for invalid function flags. */
00506         switch (flags) {
00507         case 0:
00508                 break;
00509         default:
00510                 return (__db_ferr(dbenv, "DB->del", 0));
00511         }
00512 
00513         return (0);
00514 }
00515 
00516 /*
00517  * db_fd_pp --
00518  *      DB->fd pre/post processing.
00519  *
00520  * PUBLIC: int __db_fd_pp __P((DB *, int *));
00521  */
00522 int
00523 __db_fd_pp(dbp, fdp)
00524         DB *dbp;
00525         int *fdp;
00526 {
00527         DB_ENV *dbenv;
00528         DB_THREAD_INFO *ip;
00529         DB_FH *fhp;
00530         int handle_check, ret, t_ret;
00531 
00532         dbenv = dbp->dbenv;
00533 
00534         PANIC_CHECK(dbenv);
00535         DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->fd");
00536 
00537         ENV_ENTER(dbenv, ip);
00538 
00539         /* Check for replication block. */
00540         handle_check = IS_ENV_REPLICATED(dbenv);
00541         if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0)
00542                 goto err;
00543 
00544         /*
00545          * !!!
00546          * There's no argument checking to be done.
00547          *
00548          * !!!
00549          * The actual method call is simple, do it inline.
00550          *
00551          * XXX
00552          * Truly spectacular layering violation.
00553          */
00554         if ((ret = __mp_xxx_fh(dbp->mpf, &fhp)) == 0) {
00555                 if (fhp == NULL) {
00556                         *fdp = -1;
00557                         __db_err(dbenv,
00558                             "Database does not have a valid file handle");
00559                         ret = ENOENT;
00560                 } else
00561                         *fdp = fhp->fd;
00562         }
00563 
00564         /* Release replication block. */
00565         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00566                 ret = t_ret;
00567 
00568 err:    ENV_LEAVE(dbenv, ip);
00569         return (ret);
00570 }
00571 
00572 /*
00573  * __db_get_pp --
00574  *      DB->get pre/post processing.
00575  *
00576  * PUBLIC: int __db_get_pp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
00577  */
00578 int
00579 __db_get_pp(dbp, txn, key, data, flags)
00580         DB *dbp;
00581         DB_TXN *txn;
00582         DBT *key, *data;
00583         u_int32_t flags;
00584 {
00585         DB_ENV *dbenv;
00586         DB_THREAD_INFO *ip;
00587         u_int32_t mode;
00588         int handle_check, ret, t_ret, txn_local;
00589 
00590         dbenv = dbp->dbenv;
00591         mode = 0;
00592         txn_local = 0;
00593 
00594         PANIC_CHECK(dbenv);
00595         STRIP_AUTO_COMMIT(flags);
00596         DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get");
00597 
00598         ENV_ENTER(dbenv, ip);
00599 
00600         /* Check for replication block. */
00601         handle_check = IS_ENV_REPLICATED(dbenv);
00602         if (handle_check &&
00603              (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
00604                         handle_check = 0;
00605                         goto err;
00606         }
00607 
00608         if ((ret = __db_get_arg(dbp, key, data, flags)) != 0)
00609                 goto err;
00610 
00611         if (LF_ISSET(DB_READ_UNCOMMITTED))
00612                 mode = DB_READ_UNCOMMITTED;
00613         else if ((flags & DB_OPFLAGS_MASK) == DB_CONSUME ||
00614             (flags & DB_OPFLAGS_MASK) == DB_CONSUME_WAIT) {
00615                 mode = DB_WRITELOCK;
00616                 if (IS_DB_AUTO_COMMIT(dbp, txn)) {
00617                         if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0)
00618                                 goto err;
00619                         txn_local = 1;
00620                 }
00621         }
00622 
00623         /* Check for consistent transaction usage. */
00624         if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID,
00625             mode == DB_WRITELOCK || LF_ISSET(DB_RMW) ? 0 : 1)) != 0)
00626                 goto err;
00627 
00628         ret = __db_get(dbp, txn, key, data, flags);
00629 
00630 err:    if (txn_local &&
00631             (t_ret = __db_txn_auto_resolve(dbenv, txn, 0, ret)) && ret == 0)
00632                 ret = t_ret;
00633 
00634         /* Release replication block. */
00635         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00636                 ret = t_ret;
00637         ENV_LEAVE(dbenv, ip);
00638         return (ret);
00639 }
00640 
00641 /*
00642  * __db_get --
00643  *      DB->get.
00644  *
00645  * PUBLIC: int __db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
00646  */
00647 int
00648 __db_get(dbp, txn, key, data, flags)
00649         DB *dbp;
00650         DB_TXN *txn;
00651         DBT *key, *data;
00652         u_int32_t flags;
00653 {
00654         DBC *dbc;
00655         u_int32_t mode;
00656         int ret, t_ret;
00657 
00658         mode = 0;
00659         if (LF_ISSET(DB_READ_UNCOMMITTED)) {
00660                 mode = DB_READ_UNCOMMITTED;
00661                 LF_CLR(DB_READ_UNCOMMITTED);
00662         } else if (LF_ISSET(DB_READ_COMMITTED)) {
00663                 mode = DB_READ_COMMITTED;
00664                 LF_CLR(DB_READ_COMMITTED);
00665         } else if ((flags & DB_OPFLAGS_MASK) == DB_CONSUME ||
00666             (flags & DB_OPFLAGS_MASK) == DB_CONSUME_WAIT)
00667                 mode = DB_WRITELOCK;
00668 
00669         if ((ret = __db_cursor(dbp, txn, &dbc, mode)) != 0)
00670                 return (ret);
00671 
00672         DEBUG_LREAD(dbc, txn, "DB->get", key, NULL, flags);
00673 
00674         /*
00675          * The DBC_TRANSIENT flag indicates that we're just doing a
00676          * single operation with this cursor, and that in case of
00677          * error we don't need to restore it to its old position--we're
00678          * going to close it right away.  Thus, we can perform the get
00679          * without duplicating the cursor, saving some cycles in this
00680          * common case.
00681          */
00682         F_SET(dbc, DBC_TRANSIENT);
00683 
00684         /*
00685          * SET_RET_MEM indicates that if key and/or data have no DBT
00686          * flags set and DB manages the returned-data memory, that memory
00687          * will belong to this handle, not to the underlying cursor.
00688          */
00689         SET_RET_MEM(dbc, dbp);
00690 
00691         if (LF_ISSET(~(DB_RMW | DB_MULTIPLE)) == 0)
00692                 LF_SET(DB_SET);
00693 
00694         ret = __db_c_get(dbc, key, data, flags);
00695 
00696         if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0)
00697                 ret = t_ret;
00698 
00699         return (ret);
00700 }
00701 
00702 /*
00703  * __db_get_arg --
00704  *      DB->get argument checking, used by both DB->get and DB->pget.
00705  */
00706 static int
00707 __db_get_arg(dbp, key, data, flags)
00708         const DB *dbp;
00709         const DBT *key;
00710         DBT *data;
00711         u_int32_t flags;
00712 {
00713         DB_ENV *dbenv;
00714         int check_thread, dirty, multi, ret;
00715 
00716         dbenv = dbp->dbenv;
00717 
00718         /*
00719          * Check for read-modify-write validity.  DB_RMW doesn't make sense
00720          * with CDB cursors since if you're going to write the cursor, you
00721          * had to create it with DB_WRITECURSOR.  Regardless, we check for
00722          * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it.
00723          * If this changes, confirm that DB does not itself set the DB_RMW
00724          * flag in a path where CDB may have been configured.
00725          */
00726         check_thread = dirty = 0;
00727         if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW)) {
00728                 if (!LOCKING_ON(dbenv))
00729                         return (__db_fnl(dbenv, "DB->get"));
00730                 if ((ret = __db_fcchk(dbenv, "DB->get",
00731                     flags, DB_READ_UNCOMMITTED, DB_READ_COMMITTED)) != 0)
00732                         return (ret);
00733                 if (LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED))
00734                         dirty = 1;
00735                 LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW);
00736         }
00737 
00738         multi = 0;
00739         if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
00740                 if (LF_ISSET(DB_MULTIPLE_KEY))
00741                         goto multi_err;
00742                 multi = LF_ISSET(DB_MULTIPLE) ? 1 : 0;
00743                 LF_CLR(DB_MULTIPLE);
00744         }
00745 
00746         /* Check for invalid function flags. */
00747         switch (flags) {
00748         case 0:
00749         case DB_GET_BOTH:
00750                 break;
00751         case DB_SET_RECNO:
00752                 check_thread = 1;
00753                 if (!F_ISSET(dbp, DB_AM_RECNUM))
00754                         goto err;
00755                 break;
00756         case DB_CONSUME:
00757         case DB_CONSUME_WAIT:
00758                 check_thread = 1;
00759                 if (dirty) {
00760                         __db_err(dbenv,
00761                     "%s is not supported with DB_CONSUME or DB_CONSUME_WAIT",
00762                              LF_ISSET(DB_READ_UNCOMMITTED) ?
00763                              "DB_READ_UNCOMMITTED" : "DB_READ_COMMITTED");
00764                         return (EINVAL);
00765                 }
00766                 if (multi)
00767 multi_err:              return (__db_ferr(dbenv, "DB->get", 1));
00768                 if (dbp->type == DB_QUEUE)
00769                         break;
00770                 /* FALLTHROUGH */
00771         default:
00772 err:            return (__db_ferr(dbenv, "DB->get", 0));
00773         }
00774 
00775         /*
00776          * Check for invalid key/data flags.
00777          *
00778          * XXX: Dave Krinsky
00779          * Remember to modify this when we fix the flag-returning problem.
00780          */
00781         if ((ret = __dbt_ferr(dbp, "key", key, check_thread)) != 0)
00782                 return (ret);
00783         if ((ret = __dbt_ferr(dbp, "data", data, 1)) != 0)
00784                 return (ret);
00785 
00786         if (multi) {
00787                 if (!F_ISSET(data, DB_DBT_USERMEM)) {
00788                         __db_err(dbenv,
00789                             "DB_MULTIPLE requires DB_DBT_USERMEM be set");
00790                         return (EINVAL);
00791                 }
00792                 if (F_ISSET(key, DB_DBT_PARTIAL) ||
00793                     F_ISSET(data, DB_DBT_PARTIAL)) {
00794                         __db_err(dbenv,
00795                             "DB_MULTIPLE does not support DB_DBT_PARTIAL");
00796                         return (EINVAL);
00797                 }
00798                 if (data->ulen < 1024 ||
00799                     data->ulen < dbp->pgsize || data->ulen % 1024 != 0) {
00800                         __db_err(dbenv, "%s%s",
00801                             "DB_MULTIPLE buffers must be ",
00802                             "aligned, at least page size and multiples of 1KB");
00803                         return (EINVAL);
00804                 }
00805         }
00806 
00807         return (0);
00808 }
00809 
00810 /*
00811  * __db_join_pp --
00812  *      DB->join pre/post processing.
00813  *
00814  * PUBLIC: int __db_join_pp __P((DB *, DBC **, DBC **, u_int32_t));
00815  */
00816 int
00817 __db_join_pp(primary, curslist, dbcp, flags)
00818         DB *primary;
00819         DBC **curslist, **dbcp;
00820         u_int32_t flags;
00821 {
00822         DB_ENV *dbenv;
00823         DB_THREAD_INFO *ip;
00824         int handle_check, ret, t_ret;
00825 
00826         dbenv = primary->dbenv;
00827 
00828         PANIC_CHECK(dbenv);
00829 
00830         ENV_ENTER(dbenv, ip);
00831 
00832         /* Check for replication block. */
00833         handle_check = IS_ENV_REPLICATED(dbenv);
00834         if (handle_check && (ret =
00835             __db_rep_enter(primary, 1, 0, curslist[0]->txn != NULL)) != 0) {
00836                 handle_check = 0;
00837                 goto err;
00838         }
00839 
00840         if ((ret = __db_join_arg(primary, curslist, flags)) == 0)
00841                 ret = __db_join(primary, curslist, dbcp, flags);
00842 
00843         /* Release replication block. */
00844         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00845                 ret = t_ret;
00846 
00847 err:    ENV_LEAVE(dbenv, ip);
00848         return (ret);
00849 }
00850 
00851 /*
00852  * __db_join_arg --
00853  *      Check DB->join arguments.
00854  */
00855 static int
00856 __db_join_arg(primary, curslist, flags)
00857         DB *primary;
00858         DBC **curslist;
00859         u_int32_t flags;
00860 {
00861         DB_ENV *dbenv;
00862         DB_TXN *txn;
00863         int i;
00864 
00865         dbenv = primary->dbenv;
00866 
00867         switch (flags) {
00868         case 0:
00869         case DB_JOIN_NOSORT:
00870                 break;
00871         default:
00872                 return (__db_ferr(dbenv, "DB->join", 0));
00873         }
00874 
00875         if (curslist == NULL || curslist[0] == NULL) {
00876                 __db_err(dbenv,
00877             "At least one secondary cursor must be specified to DB->join");
00878                 return (EINVAL);
00879         }
00880 
00881         txn = curslist[0]->txn;
00882         for (i = 1; curslist[i] != NULL; i++)
00883                 if (curslist[i]->txn != txn) {
00884                         __db_err(dbenv,
00885                     "All secondary cursors must share the same transaction");
00886                         return (EINVAL);
00887                 }
00888 
00889         return (0);
00890 }
00891 
00892 /*
00893  * __db_key_range_pp --
00894  *      DB->key_range pre/post processing.
00895  *
00896  * PUBLIC: int __db_key_range_pp
00897  * PUBLIC:     __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t));
00898  */
00899 int
00900 __db_key_range_pp(dbp, txn, key, kr, flags)
00901         DB *dbp;
00902         DB_TXN *txn;
00903         DBT *key;
00904         DB_KEY_RANGE *kr;
00905         u_int32_t flags;
00906 {
00907         DBC *dbc;
00908         DB_ENV *dbenv;
00909         DB_THREAD_INFO *ip;
00910         int handle_check, ret, t_ret;
00911 
00912         dbenv = dbp->dbenv;
00913 
00914         PANIC_CHECK(dbp->dbenv);
00915         DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->key_range");
00916 
00917         /*
00918          * !!!
00919          * The actual argument checking is simple, do it inline, outside of
00920          * the replication block.
00921          */
00922         if (flags != 0)
00923                 return (__db_ferr(dbenv, "DB->key_range", 0));
00924 
00925         ENV_ENTER(dbenv, ip);
00926 
00927         /* Check for replication block. */
00928         handle_check = IS_ENV_REPLICATED(dbenv);
00929         if (handle_check &&
00930              (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
00931                 handle_check = 0;
00932                 goto err;
00933         }
00934 
00935         /* Check for consistent transaction usage. */
00936         if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0)
00937                 goto err;
00938 
00939         /*
00940          * !!!
00941          * The actual method call is simple, do it inline.
00942          */
00943         switch (dbp->type) {
00944         case DB_BTREE:
00945                 /* Acquire a cursor. */
00946                 if ((ret = __db_cursor(dbp, txn, &dbc, 0)) != 0)
00947                         break;
00948 
00949                 DEBUG_LWRITE(dbc, NULL, "bam_key_range", NULL, NULL, 0);
00950 
00951                 ret = __bam_key_range(dbc, key, kr, flags);
00952 
00953                 if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
00954                         ret = t_ret;
00955                 break;
00956         case DB_HASH:
00957         case DB_QUEUE:
00958         case DB_RECNO:
00959                 ret = __dbh_am_chk(dbp, DB_OK_BTREE);
00960                 break;
00961         case DB_UNKNOWN:
00962         default:
00963                 ret = __db_unknown_type(dbenv, "DB->key_range", dbp->type);
00964                 break;
00965         }
00966 
00967 err:    /* Release replication block. */
00968         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00969                 ret = t_ret;
00970 
00971         ENV_LEAVE(dbenv, ip);
00972         return (ret);
00973 }
00974 
00975 /*
00976  * __db_open_pp --
00977  *      DB->open pre/post processing.
00978  *
00979  * PUBLIC: int __db_open_pp __P((DB *, DB_TXN *,
00980  * PUBLIC:     const char *, const char *, DBTYPE, u_int32_t, int));
00981  */
00982 int
00983 __db_open_pp(dbp, txn, fname, dname, type, flags, mode)
00984         DB *dbp;
00985         DB_TXN *txn;
00986         const char *fname, *dname;
00987         DBTYPE type;
00988         u_int32_t flags;
00989         int mode;
00990 {
00991         DB_ENV *dbenv;
00992         DB_THREAD_INFO *ip;
00993         int handle_check, nosync, remove_me, ret, t_ret, txn_local;
00994 
00995         dbenv = dbp->dbenv;
00996         nosync = 1;
00997         remove_me = txn_local = 0;
00998         handle_check = 0;
00999 
01000         PANIC_CHECK(dbenv);
01001 
01002         ENV_ENTER(dbenv, ip);
01003 
01004         /*
01005          * Save the file and database names and flags.  We do this here
01006          * because we don't pass all of the flags down into the actual
01007          * DB->open method call, we strip DB_AUTO_COMMIT at this layer.
01008          */
01009         if ((fname != NULL &&
01010             (ret = __os_strdup(dbenv, fname, &dbp->fname)) != 0))
01011                 goto err;
01012         if ((dname != NULL &&
01013             (ret = __os_strdup(dbenv, dname, &dbp->dname)) != 0))
01014                 goto err;
01015         dbp->open_flags = flags;
01016 
01017         /* Save the current DB handle flags for refresh. */
01018         dbp->orig_flags = dbp->flags;
01019 
01020         /* Check for replication block. */
01021         handle_check = IS_ENV_REPLICATED(dbenv);
01022         if (handle_check &&
01023             (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
01024                 handle_check = 0;
01025                 goto err;
01026         }
01027 
01028         /*
01029          * Create local transaction as necessary, check for consistent
01030          * transaction usage.
01031          */
01032         if (IS_ENV_AUTO_COMMIT(dbenv, txn, flags)) {
01033                 if ((ret = __db_txn_auto_init(dbenv, &txn)) != 0)
01034                         goto err;
01035                 txn_local = 1;
01036         } else
01037                 if (txn != NULL && !TXN_ON(dbenv)) {
01038                         ret = __db_not_txn_env(dbenv);
01039                         goto err;
01040                 }
01041         LF_CLR(DB_AUTO_COMMIT);
01042 
01043         /*
01044          * We check arguments after possibly creating a local transaction,
01045          * which is unusual -- the reason is some flags are illegal if any
01046          * kind of transaction is in effect.
01047          */
01048         if ((ret = __db_open_arg(dbp, txn, fname, dname, type, flags)) == 0)
01049                 if ((ret = __db_open(dbp, txn, fname, dname, type,
01050                     flags, mode, PGNO_BASE_MD)) != 0)
01051                         goto txnerr;
01052 
01053         /*
01054          * You can open the database that describes the subdatabases in the
01055          * rest of the file read-only.  The content of each key's data is
01056          * unspecified and applications should never be adding new records
01057          * or updating existing records.  However, during recovery, we need
01058          * to open these databases R/W so we can redo/undo changes in them.
01059          * Likewise, we need to open master databases read/write during
01060          * rename and remove so we can be sure they're fully sync'ed, so
01061          * we provide an override flag for the purpose.
01062          */
01063         if (dname == NULL && !IS_RECOVERING(dbenv) && !LF_ISSET(DB_RDONLY) &&
01064             !LF_ISSET(DB_RDWRMASTER) && F_ISSET(dbp, DB_AM_SUBDB)) {
01065                 __db_err(dbenv,
01066     "files containing multiple databases may only be opened read-only");
01067                 ret = EINVAL;
01068                 goto txnerr;
01069         }
01070 
01071         /*
01072          * Success: file creations have to be synchronous, otherwise we don't
01073          * care.
01074          */
01075         if (F_ISSET(dbp, DB_AM_CREATED | DB_AM_CREATED_MSTR))
01076                 nosync = 0;
01077 
01078         /* Success: don't discard the file on close. */
01079         F_CLR(dbp, DB_AM_DISCARD | DB_AM_CREATED | DB_AM_CREATED_MSTR);
01080 
01081         /*
01082          * If not transactional, remove the databases/subdatabases.  If we're
01083          * transactional, the child transaction abort cleans up.
01084          */
01085 txnerr: if (ret != 0 && txn == NULL) {
01086                 remove_me = F_ISSET(dbp, DB_AM_CREATED);
01087                 if (F_ISSET(dbp, DB_AM_CREATED_MSTR) ||
01088                     (dname == NULL && remove_me))
01089                         /* Remove file. */
01090                         (void)__db_remove_int(dbp, txn, fname, NULL, DB_FORCE);
01091                 else if (remove_me)
01092                         /* Remove subdatabase. */
01093                         (void)__db_remove_int(dbp, txn, fname, dname, DB_FORCE);
01094         }
01095 
01096         if (txn_local && (t_ret =
01097              __db_txn_auto_resolve(dbenv, txn, nosync, ret)) && ret == 0)
01098                 ret = t_ret;
01099 
01100 err:    /* Release replication block. */
01101         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
01102                 ret = t_ret;
01103 
01104         ENV_LEAVE(dbenv, ip);
01105         return (ret);
01106 }
01107 
01108 /*
01109  * __db_open_arg --
01110  *      Check DB->open arguments.
01111  */
01112 static int
01113 __db_open_arg(dbp, txn, fname, dname, type, flags)
01114         DB *dbp;
01115         DB_TXN *txn;
01116         const char *fname, *dname;
01117         DBTYPE type;
01118         u_int32_t flags;
01119 {
01120         DB_ENV *dbenv;
01121         u_int32_t ok_flags;
01122         int ret;
01123 
01124         dbenv = dbp->dbenv;
01125 
01126         /* Validate arguments. */
01127 #undef  OKFLAGS
01128 #define OKFLAGS                                                         \
01129         (DB_AUTO_COMMIT | DB_CREATE | DB_EXCL | DB_FCNTL_LOCKING |      \
01130         DB_NOMMAP | DB_NO_AUTO_COMMIT | DB_RDONLY | DB_RDWRMASTER |     \
01131         DB_READ_UNCOMMITTED | DB_THREAD | DB_TRUNCATE | DB_WRITEOPEN)
01132         if ((ret = __db_fchk(dbenv, "DB->open", flags, OKFLAGS)) != 0)
01133                 return (ret);
01134         if (LF_ISSET(DB_EXCL) && !LF_ISSET(DB_CREATE))
01135                 return (__db_ferr(dbenv, "DB->open", 1));
01136         if (LF_ISSET(DB_RDONLY) && LF_ISSET(DB_CREATE))
01137                 return (__db_ferr(dbenv, "DB->open", 1));
01138 
01139 #ifdef  HAVE_VXWORKS
01140         if (LF_ISSET(DB_TRUNCATE)) {
01141                 __db_err(dbenv, "DB_TRUNCATE not supported on VxWorks");
01142                 return (DB_OPNOTSUP);
01143         }
01144 #endif
01145         switch (type) {
01146         case DB_UNKNOWN:
01147                 if (LF_ISSET(DB_CREATE|DB_TRUNCATE)) {
01148                         __db_err(dbenv,
01149             "DB_UNKNOWN type specified with DB_CREATE or DB_TRUNCATE");
01150                         return (EINVAL);
01151                 }
01152                 ok_flags = 0;
01153                 break;
01154         case DB_BTREE:
01155                 ok_flags = DB_OK_BTREE;
01156                 break;
01157         case DB_HASH:
01158 #ifndef HAVE_HASH
01159                 return (__db_no_hash_am(dbenv));
01160 #endif
01161                 ok_flags = DB_OK_HASH;
01162                 break;
01163         case DB_QUEUE:
01164 #ifndef HAVE_QUEUE
01165                 return (__db_no_queue_am(dbenv));
01166 #endif
01167                 ok_flags = DB_OK_QUEUE;
01168                 break;
01169         case DB_RECNO:
01170                 ok_flags = DB_OK_RECNO;
01171                 break;
01172         default:
01173                 __db_err(dbenv, "unknown type: %lu", (u_long)type);
01174                 return (EINVAL);
01175         }
01176         if (ok_flags)
01177                 DB_ILLEGAL_METHOD(dbp, ok_flags);
01178 
01179         /* The environment may have been created, but never opened. */
01180         if (!F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_OPEN_CALLED)) {
01181                 __db_err(dbenv, "environment not yet opened");
01182                 return (EINVAL);
01183         }
01184 
01185         /*
01186          * Historically, you could pass in an environment that didn't have a
01187          * mpool, and DB would create a private one behind the scenes.  This
01188          * no longer works.
01189          */
01190         if (!F_ISSET(dbenv, DB_ENV_DBLOCAL) && !MPOOL_ON(dbenv)) {
01191                 __db_err(dbenv, "environment did not include a memory pool");
01192                 return (EINVAL);
01193         }
01194 
01195         /*
01196          * You can't specify threads during DB->open if subsystems in the
01197          * environment weren't configured with them.
01198          */
01199         if (LF_ISSET(DB_THREAD) &&
01200             !F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_THREAD)) {
01201                 __db_err(dbenv, "environment not created using DB_THREAD");
01202                 return (EINVAL);
01203         }
01204 
01205         /* DB_TRUNCATE is neither transaction recoverable nor lockable. */
01206         if (LF_ISSET(DB_TRUNCATE) && (LOCKING_ON(dbenv) || txn != NULL)) {
01207                 __db_err(dbenv,
01208                     "DB_TRUNCATE illegal with %s specified",
01209                     LOCKING_ON(dbenv) ? "locking" : "transactions");
01210                 return (EINVAL);
01211         }
01212 
01213         /* Subdatabase checks. */
01214         if (dname != NULL) {
01215                 /* QAM can only be done on in-memory subdatabases. */
01216                 if (type == DB_QUEUE && fname != NULL) {
01217                         __db_err(dbenv, "Queue databases must be one-per-file");
01218                         return (EINVAL);
01219                 }
01220 
01221                 /*
01222                  * Named in-memory databases can't support certain flags,
01223                  * so check here.
01224                  */
01225                 if (fname == NULL)
01226                         F_CLR(dbp, DB_AM_CHKSUM | DB_AM_ENCRYPT);
01227         }
01228 
01229         return (0);
01230 }
01231 
01232 /*
01233  * __db_pget_pp --
01234  *      DB->pget pre/post processing.
01235  *
01236  * PUBLIC: int __db_pget_pp
01237  * PUBLIC:     __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t));
01238  */
01239 int
01240 __db_pget_pp(dbp, txn, skey, pkey, data, flags)
01241         DB *dbp;
01242         DB_TXN *txn;
01243         DBT *skey, *pkey, *data;
01244         u_int32_t flags;
01245 {
01246         DB_ENV *dbenv;
01247         DB_THREAD_INFO *ip;
01248         int handle_check, ret, t_ret;
01249 
01250         dbenv = dbp->dbenv;
01251 
01252         PANIC_CHECK(dbenv);
01253         DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->pget");
01254 
01255         ENV_ENTER(dbenv, ip);
01256 
01257         /* Check for replication block. */
01258         handle_check = IS_ENV_REPLICATED(dbenv);
01259         if (handle_check &&
01260             (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
01261                 handle_check = 0;
01262                 goto err;
01263         }
01264 
01265         if ((ret = __db_pget_arg(dbp, pkey, flags)) != 0 ||
01266             (ret = __db_get_arg(dbp, skey, data, flags)) != 0)
01267                 goto err;
01268 
01269         ret = __db_pget(dbp, txn, skey, pkey, data, flags);
01270 
01271 err:    /* Release replication block. */
01272         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
01273                 ret = t_ret;
01274 
01275         ENV_LEAVE(dbenv, ip);
01276         return (ret);
01277 }
01278 
01279 /*
01280  * __db_pget --
01281  *      DB->pget.
01282  *
01283  * PUBLIC: int __db_pget
01284  * PUBLIC:     __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t));
01285  */
01286 int
01287 __db_pget(dbp, txn, skey, pkey, data, flags)
01288         DB *dbp;
01289         DB_TXN *txn;
01290         DBT *skey, *pkey, *data;
01291         u_int32_t flags;
01292 {
01293         DBC *dbc;
01294         u_int32_t mode;
01295         int ret, t_ret;
01296 
01297         if (LF_ISSET(DB_READ_UNCOMMITTED)) {
01298                 mode = DB_READ_UNCOMMITTED;
01299                 LF_CLR(DB_READ_UNCOMMITTED);
01300         } else if (LF_ISSET(DB_READ_COMMITTED)) {
01301                 mode = DB_READ_COMMITTED;
01302                 LF_CLR(DB_READ_COMMITTED);
01303         } else
01304                 mode = 0;
01305 
01306         if ((ret = __db_cursor(dbp, txn, &dbc, mode)) != 0)
01307                 return (ret);
01308 
01309         SET_RET_MEM(dbc, dbp);
01310 
01311         DEBUG_LREAD(dbc, txn, "__db_pget", skey, NULL, flags);
01312 
01313         /*
01314          * !!!
01315          * The actual method call is simple, do it inline.
01316          *
01317          * The underlying cursor pget will fill in a default DBT for null
01318          * pkeys, and use the cursor's returned-key memory internally to
01319          * store any intermediate primary keys.  However, we've just set
01320          * the returned-key memory to the DB handle's key memory, which
01321          * is unsafe to use if the DB handle is threaded.  If the pkey
01322          * argument is NULL, use the DBC-owned returned-key memory
01323          * instead;  it'll go away when we close the cursor before we
01324          * return, but in this case that's just fine, as we're not
01325          * returning the primary key.
01326          */
01327         if (pkey == NULL)
01328                 dbc->rkey = &dbc->my_rkey;
01329 
01330         /*
01331          * The cursor is just a perfectly ordinary secondary database cursor.
01332          * Call its c_pget() method to do the dirty work.
01333          */
01334         if (flags == 0 || flags == DB_RMW)
01335                 flags |= DB_SET;
01336 
01337         ret = __db_c_pget(dbc, skey, pkey, data, flags);
01338 
01339         if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
01340                 ret = t_ret;
01341 
01342         return (ret);
01343 }
01344 
01345 /*
01346  * __db_pget_arg --
01347  *      Check DB->pget arguments.
01348  */
01349 static int
01350 __db_pget_arg(dbp, pkey, flags)
01351         DB *dbp;
01352         DBT *pkey;
01353         u_int32_t flags;
01354 {
01355         DB_ENV *dbenv;
01356         int ret;
01357 
01358         dbenv = dbp->dbenv;
01359 
01360         if (!F_ISSET(dbp, DB_AM_SECONDARY)) {
01361                 __db_err(dbenv,
01362                     "DB->pget may only be used on secondary indices");
01363                 return (EINVAL);
01364         }
01365 
01366         if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
01367                 __db_err(dbenv,
01368         "DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices");
01369                 return (EINVAL);
01370         }
01371 
01372         /* DB_CONSUME makes no sense on a secondary index. */
01373         LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_RMW);
01374         switch (flags) {
01375         case DB_CONSUME:
01376         case DB_CONSUME_WAIT:
01377                 return (__db_ferr(dbenv, "DB->pget", 0));
01378         default:
01379                 /* __db_get_arg will catch the rest. */
01380                 break;
01381         }
01382 
01383         /*
01384          * We allow the pkey field to be NULL, so that we can make the
01385          * two-DBT get calls into wrappers for the three-DBT ones.
01386          */
01387         if (pkey != NULL &&
01388             (ret = __dbt_ferr(dbp, "primary key", pkey, 1)) != 0)
01389                 return (ret);
01390 
01391         /* But the pkey field can't be NULL if we're doing a DB_GET_BOTH. */
01392         if (pkey == NULL && flags == DB_GET_BOTH) {
01393                 __db_err(dbenv,
01394                     "DB_GET_BOTH on a secondary index requires a primary key");
01395                 return (EINVAL);
01396         }
01397 
01398         return (0);
01399 }
01400 
01401 /*
01402  * __db_put_pp --
01403  *      DB->put pre/post processing.
01404  *
01405  * PUBLIC: int __db_put_pp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
01406  */
01407 int
01408 __db_put_pp(dbp, txn, key, data, flags)
01409         DB *dbp;
01410         DB_TXN *txn;
01411         DBT *key, *data;
01412         u_int32_t flags;
01413 {
01414         DB_ENV *dbenv;
01415         DB_THREAD_INFO *ip;
01416         int handle_check, ret, txn_local, t_ret;
01417 
01418         dbenv = dbp->dbenv;
01419         txn_local = 0;
01420 
01421         PANIC_CHECK(dbenv);
01422         STRIP_AUTO_COMMIT(flags);
01423         DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->put");
01424 
01425         ENV_ENTER(dbenv, ip);
01426 
01427         /* Check for replication block. */
01428         handle_check = IS_ENV_REPLICATED(dbenv);
01429         if (handle_check &&
01430             (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
01431                 handle_check = 0;
01432                 goto err;
01433         }
01434 
01435         if ((ret = __db_put_arg(dbp, key, data, flags)) != 0)
01436                 goto err;
01437 
01438         /* Create local transaction as necessary. */
01439         if (IS_DB_AUTO_COMMIT(dbp, txn)) {
01440                 if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0)
01441                         goto err;
01442                 txn_local = 1;
01443         }
01444 
01445         /* Check for consistent transaction usage. */
01446         if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
01447                 goto err;
01448 
01449         ret = __db_put(dbp, txn, key, data, flags);
01450 
01451 err:    if (txn_local &&
01452             (t_ret = __db_txn_auto_resolve(dbenv, txn, 0, ret)) && ret == 0)
01453                 ret = t_ret;
01454 
01455         /* Release replication block. */
01456         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
01457                 ret = t_ret;
01458         ENV_LEAVE(dbenv, ip);
01459         return (ret);
01460 }
01461 
01462 /*
01463  * __db_put_arg --
01464  *      Check DB->put arguments.
01465  */
01466 static int
01467 __db_put_arg(dbp, key, data, flags)
01468         DB *dbp;
01469         DBT *key, *data;
01470         u_int32_t flags;
01471 {
01472         DB_ENV *dbenv;
01473         int ret, returnkey;
01474 
01475         dbenv = dbp->dbenv;
01476         returnkey = 0;
01477 
01478         /* Check for changes to a read-only tree. */
01479         if (DB_IS_READONLY(dbp))
01480                 return (__db_rdonly(dbenv, "DB->put"));
01481 
01482         /* Check for puts on a secondary. */
01483         if (F_ISSET(dbp, DB_AM_SECONDARY)) {
01484                 __db_err(dbenv, "DB->put forbidden on secondary indices");
01485                 return (EINVAL);
01486         }
01487 
01488         /* Check for invalid function flags. */
01489         switch (flags) {
01490         case 0:
01491         case DB_NOOVERWRITE:
01492                 break;
01493         case DB_APPEND:
01494                 if (dbp->type != DB_RECNO && dbp->type != DB_QUEUE)
01495                         goto err;
01496                 returnkey = 1;
01497                 break;
01498         case DB_NODUPDATA:
01499                 if (F_ISSET(dbp, DB_AM_DUPSORT))
01500                         break;
01501                 /* FALLTHROUGH */
01502         default:
01503 err:            return (__db_ferr(dbenv, "DB->put", 0));
01504         }
01505 
01506         /* Check for invalid key/data flags. */
01507         if ((ret = __dbt_ferr(dbp, "key", key, returnkey)) != 0)
01508                 return (ret);
01509         if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
01510                 return (ret);
01511 
01512         /* Keys shouldn't have partial flags during a put. */
01513         if (F_ISSET(key, DB_DBT_PARTIAL))
01514                 return (__db_ferr(dbenv, "key DBT", 0));
01515 
01516         /* Check for partial puts in the presence of duplicates. */
01517         if (F_ISSET(data, DB_DBT_PARTIAL) &&
01518             (F_ISSET(dbp, DB_AM_DUP) || F_ISSET(key, DB_DBT_DUPOK))) {
01519                 __db_err(dbenv,
01520 "a partial put in the presence of duplicates requires a cursor operation");
01521                 return (EINVAL);
01522         }
01523 
01524         return (0);
01525 }
01526 
01527 /*
01528  * __db_compact_pp --
01529  *      DB->compact pre/post processing.
01530  *
01531  * PUBLIC: int __db_compact_pp __P((DB *, DB_TXN *,
01532  * PUBLIC:       DBT *, DBT *, DB_COMPACT *, u_int32_t, DBT *));
01533  */
01534 int
01535 __db_compact_pp(dbp, txn, start, stop, c_data, flags, end)
01536         DB *dbp;
01537         DB_TXN *txn;
01538         DBT *start, *stop;
01539         DB_COMPACT *c_data;
01540         u_int32_t flags;
01541         DBT *end;
01542 {
01543         DB_COMPACT *dp, l_data;
01544         DB_ENV *dbenv;
01545         DB_THREAD_INFO *ip;
01546         int handle_check, ret, t_ret;
01547 
01548         dbenv = dbp->dbenv;
01549 
01550         PANIC_CHECK(dbenv);
01551         DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->compact");
01552 
01553         /*
01554          * !!!
01555          * The actual argument checking is simple, do it inline, outside of
01556          * the replication block.
01557          */
01558         if ((flags & ~DB_COMPACT_FLAGS) != 0)
01559                 return (__db_ferr(dbenv, "DB->compact", 0));
01560 
01561         /* Check for changes to a read-only database. */
01562         if (DB_IS_READONLY(dbp))
01563                 return (__db_rdonly(dbenv, "DB->compact"));
01564 
01565         ENV_ENTER(dbenv, ip);
01566 
01567         /* Check for replication block. */
01568         handle_check = IS_ENV_REPLICATED(dbenv);
01569         if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) {
01570                 handle_check = 0;
01571                 goto err;
01572         }
01573 
01574         if (c_data == NULL) {
01575                 dp = &l_data;
01576                 memset(dp, 0, sizeof(*dp));
01577         } else
01578                 dp = c_data;
01579 
01580         switch (dbp->type) {
01581         case DB_HASH:
01582                 if (!LF_ISSET(DB_FREELIST_ONLY))
01583                         goto err;
01584                 /* FALLTHROUGH */
01585         case DB_BTREE:
01586         case DB_RECNO:
01587                 ret = __bam_compact(dbp, txn, start, stop, dp, flags, end);
01588                 break;
01589 
01590         default:
01591 err:            ret = __dbh_am_chk(dbp, DB_OK_BTREE);
01592                 break;
01593         }
01594 
01595         /* Release replication block. */
01596         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
01597                 ret = t_ret;
01598 
01599         ENV_LEAVE(dbenv, ip);
01600         return (ret);
01601 }
01602 
01603 /*
01604  * __db_sync_pp --
01605  *      DB->sync pre/post processing.
01606  *
01607  * PUBLIC: int __db_sync_pp __P((DB *, u_int32_t));
01608  */
01609 int
01610 __db_sync_pp(dbp, flags)
01611         DB *dbp;
01612         u_int32_t flags;
01613 {
01614         DB_ENV *dbenv;
01615         DB_THREAD_INFO *ip;
01616         int handle_check, ret, t_ret;
01617 
01618         dbenv = dbp->dbenv;
01619 
01620         PANIC_CHECK(dbenv);
01621         DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync");
01622 
01623         /*
01624          * !!!
01625          * The actual argument checking is simple, do it inline, outside of
01626          * the replication block.
01627          */
01628         if (flags != 0)
01629                 return (__db_ferr(dbenv, "DB->sync", 0));
01630 
01631         ENV_ENTER(dbenv, ip);
01632 
01633         /* Check for replication block. */
01634         handle_check = IS_ENV_REPLICATED(dbenv);
01635         if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) {
01636                 handle_check = 0;
01637                 goto err;
01638         }
01639 
01640         ret = __db_sync(dbp);
01641 
01642         /* Release replication block. */
01643         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
01644                 ret = t_ret;
01645 
01646 err:    ENV_LEAVE(dbenv, ip);
01647         return (ret);
01648 }
01649 
01650 /*
01651  * __db_c_close_pp --
01652  *      DBC->c_close pre/post processing.
01653  *
01654  * PUBLIC: int __db_c_close_pp __P((DBC *));
01655  */
01656 int
01657 __db_c_close_pp(dbc)
01658         DBC *dbc;
01659 {
01660         DB_ENV *dbenv;
01661         DB_THREAD_INFO *ip;
01662         DB *dbp;
01663         int handle_check, ret, t_ret;
01664 
01665         dbp = dbc->dbp;
01666         dbenv = dbp->dbenv;
01667 
01668         PANIC_CHECK(dbenv);
01669         ENV_ENTER(dbenv, ip);
01670 
01671         /*
01672          * If the cursor is already closed we have a serious problem, and we
01673          * assume that the cursor isn't on the active queue.  Don't do any of
01674          * the remaining cursor close processing.
01675          */
01676         if (!F_ISSET(dbc, DBC_ACTIVE)) {
01677                 if (dbp != NULL)
01678                         __db_err(dbenv, "Closing already-closed cursor");
01679                 DB_ASSERT(0);
01680                 ret = EINVAL;
01681                 goto err;
01682         }
01683 
01684         /* Check for replication block. */
01685         handle_check = dbc->txn == NULL && IS_ENV_REPLICATED(dbenv);
01686         ret = __db_c_close(dbc);
01687 
01688         /* Release replication block. */
01689         if (handle_check &&
01690             (t_ret = __op_rep_exit(dbenv)) != 0 && ret == 0)
01691                 ret = t_ret;
01692 
01693 err:    ENV_LEAVE(dbenv, ip);
01694         return (ret);
01695 }
01696 
01697 /*
01698  * __db_c_count_pp --
01699  *      DBC->c_count pre/post processing.
01700  *
01701  * PUBLIC: int __db_c_count_pp __P((DBC *, db_recno_t *, u_int32_t));
01702  */
01703 int
01704 __db_c_count_pp(dbc, recnop, flags)
01705         DBC *dbc;
01706         db_recno_t *recnop;
01707         u_int32_t flags;
01708 {
01709         DB_ENV *dbenv;
01710         DB_THREAD_INFO *ip;
01711         DB *dbp;
01712         int ret;
01713 
01714         dbp = dbc->dbp;
01715         dbenv = dbp->dbenv;
01716 
01717         PANIC_CHECK(dbenv);
01718 
01719         /*
01720          * !!!
01721          * The actual argument checking is simple, do it inline, outside of
01722          * the replication block.
01723          *
01724          * The cursor must be initialized, return EINVAL for an invalid cursor.
01725          */
01726         if (flags != 0)
01727                 return (__db_ferr(dbenv, "DBcursor->count", 0));
01728 
01729         if (!IS_INITIALIZED(dbc))
01730                 return (__db_curinval(dbenv));
01731 
01732         ENV_ENTER(dbenv, ip);
01733 
01734         ret = __db_c_count(dbc, recnop);
01735         ENV_LEAVE(dbenv, ip);
01736         return (ret);
01737 }
01738 
01739 /*
01740  * __db_c_del_pp --
01741  *      DBC->c_del pre/post processing.
01742  *
01743  * PUBLIC: int __db_c_del_pp __P((DBC *, u_int32_t));
01744  */
01745 int
01746 __db_c_del_pp(dbc, flags)
01747         DBC *dbc;
01748         u_int32_t flags;
01749 {
01750         DB *dbp;
01751         DB_ENV *dbenv;
01752         DB_THREAD_INFO *ip;
01753         int ret;
01754 
01755         dbp = dbc->dbp;
01756         dbenv = dbp->dbenv;
01757 
01758         PANIC_CHECK(dbenv);
01759 
01760         if ((ret = __db_c_del_arg(dbc, flags)) != 0)
01761                 return (ret);
01762 
01763         ENV_ENTER(dbenv, ip);
01764 
01765         /* Check for consistent transaction usage. */
01766         if ((ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0)
01767                 goto err;
01768 
01769         DEBUG_LWRITE(dbc, dbc->txn, "DBcursor->del", NULL, NULL, flags);
01770         ret = __db_c_del(dbc, flags);
01771 err:
01772         ENV_LEAVE(dbenv, ip);
01773         return (ret);
01774 }
01775 
01776 /*
01777  * __db_c_del_arg --
01778  *      Check DBC->c_del arguments.
01779  */
01780 static int
01781 __db_c_del_arg(dbc, flags)
01782         DBC *dbc;
01783         u_int32_t flags;
01784 {
01785         DB *dbp;
01786         DB_ENV *dbenv;
01787 
01788         dbp = dbc->dbp;
01789         dbenv = dbp->dbenv;
01790 
01791         /* Check for changes to a read-only tree. */
01792         if (DB_IS_READONLY(dbp))
01793                 return (__db_rdonly(dbenv, "DBcursor->del"));
01794 
01795         /* Check for invalid function flags. */
01796         switch (flags) {
01797         case 0:
01798                 break;
01799         case DB_UPDATE_SECONDARY:
01800                 DB_ASSERT(F_ISSET(dbp, DB_AM_SECONDARY));
01801                 break;
01802         default:
01803                 return (__db_ferr(dbenv, "DBcursor->del", 0));
01804         }
01805 
01806         /*
01807          * The cursor must be initialized, return EINVAL for an invalid cursor,
01808          * otherwise 0.
01809          */
01810         if (!IS_INITIALIZED(dbc))
01811                 return (__db_curinval(dbenv));
01812 
01813         return (0);
01814 }
01815 
01816 /*
01817  * __db_c_dup_pp --
01818  *      DBC->c_dup pre/post processing.
01819  *
01820  * PUBLIC: int __db_c_dup_pp __P((DBC *, DBC **, u_int32_t));
01821  */
01822 int
01823 __db_c_dup_pp(dbc, dbcp, flags)
01824         DBC *dbc, **dbcp;
01825         u_int32_t flags;
01826 {
01827         DB *dbp;
01828         DB_ENV *dbenv;
01829         DB_THREAD_INFO *ip;
01830         int ret;
01831 
01832         dbp = dbc->dbp;
01833         dbenv = dbp->dbenv;
01834 
01835         PANIC_CHECK(dbenv);
01836 
01837         /*
01838          * !!!
01839          * The actual argument checking is simple, do it inline, outside of
01840          * the replication block.
01841          */
01842         if (flags != 0 && flags != DB_POSITION)
01843                 return (__db_ferr(dbenv, "DBcursor->dup", 0));
01844 
01845         ENV_ENTER(dbenv, ip);
01846 
01847         ret = __db_c_dup(dbc, dbcp, flags);
01848         ENV_LEAVE(dbenv, ip);
01849         return (ret);
01850 }
01851 
01852 /*
01853  * __db_c_get_pp --
01854  *      DBC->c_get pre/post processing.
01855  *
01856  * PUBLIC: int __db_c_get_pp __P((DBC *, DBT *, DBT *, u_int32_t));
01857  */
01858 int
01859 __db_c_get_pp(dbc, key, data, flags)
01860         DBC *dbc;
01861         DBT *key, *data;
01862         u_int32_t flags;
01863 {
01864         DB *dbp;
01865         DB_ENV *dbenv;
01866         int ret;
01867         DB_THREAD_INFO *ip;
01868 
01869         dbp = dbc->dbp;
01870         dbenv = dbp->dbenv;
01871 
01872         PANIC_CHECK(dbenv);
01873 
01874         if ((ret = __db_c_get_arg(dbc, key, data, flags)) != 0)
01875                 return (ret);
01876 
01877         ENV_ENTER(dbenv, ip);
01878 
01879         DEBUG_LREAD(dbc, dbc->txn, "DBcursor->get",
01880             flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags);
01881         ret = __db_c_get(dbc, key, data, flags);
01882 
01883         ENV_LEAVE(dbenv, ip);
01884         return (ret);
01885 }
01886 
01887 /*
01888  * __db_c_get_arg --
01889  *      Common DBC->get argument checking, used by both DBC->get and DBC->pget.
01890  */
01891 static int
01892 __db_c_get_arg(dbc, key, data, flags)
01893         DBC *dbc;
01894         DBT *key, *data;
01895         u_int32_t flags;
01896 {
01897         DB *dbp;
01898         DB_ENV *dbenv;
01899         int dirty, multi, ret;
01900 
01901         dbp = dbc->dbp;
01902         dbenv = dbp->dbenv;
01903 
01904         /*
01905          * Typically in checking routines that modify the flags, we have
01906          * to save them and restore them, because the checking routine
01907          * calls the work routine.  However, this is a pure-checking
01908          * routine which returns to a function that calls the work routine,
01909          * so it's OK that we do not save and restore the flags, even though
01910          * we modify them.
01911          *
01912          * Check for read-modify-write validity.  DB_RMW doesn't make sense
01913          * with CDB cursors since if you're going to write the cursor, you
01914          * had to create it with DB_WRITECURSOR.  Regardless, we check for
01915          * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it.
01916          * If this changes, confirm that DB does not itself set the DB_RMW
01917          * flag in a path where CDB may have been configured.
01918          */
01919         dirty = 0;
01920         if (LF_ISSET(DB_READ_UNCOMMITTED | DB_RMW)) {
01921                 if (!LOCKING_ON(dbenv))
01922                         return (__db_fnl(dbenv, "DBcursor->get"));
01923                 if (LF_ISSET(DB_READ_UNCOMMITTED))
01924                         dirty = 1;
01925                 LF_CLR(DB_READ_UNCOMMITTED | DB_RMW);
01926         }
01927 
01928         multi = 0;
01929         if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
01930                 multi = 1;
01931                 if (LF_ISSET(DB_MULTIPLE) && LF_ISSET(DB_MULTIPLE_KEY))
01932                         goto multi_err;
01933                 LF_CLR(DB_MULTIPLE | DB_MULTIPLE_KEY);
01934         }
01935 
01936         /* Check for invalid function flags. */
01937         switch (flags) {
01938         case DB_CONSUME:
01939         case DB_CONSUME_WAIT:
01940                 if (dirty) {
01941                         __db_err(dbenv,
01942     "DB_READ_UNCOMMITTED is not supported with DB_CONSUME or DB_CONSUME_WAIT");
01943                         return (EINVAL);
01944                 }
01945                 if (dbp->type != DB_QUEUE)
01946                         goto err;
01947                 break;
01948         case DB_CURRENT:
01949         case DB_FIRST:
01950         case DB_GET_BOTH:
01951         case DB_GET_BOTH_RANGE:
01952         case DB_NEXT:
01953         case DB_NEXT_DUP:
01954         case DB_NEXT_NODUP:
01955         case DB_SET:
01956         case DB_SET_RANGE:
01957                 break;
01958         case DB_LAST:
01959         case DB_PREV:
01960         case DB_PREV_NODUP:
01961                 if (multi)
01962 multi_err:              return (__db_ferr(dbenv, "DBcursor->get", 1));
01963                 break;
01964         case DB_GET_BOTHC:
01965                 if (dbp->type == DB_QUEUE)
01966                         goto err;
01967                 break;
01968         case DB_GET_RECNO:
01969                 /*
01970                  * The one situation in which this might be legal with a
01971                  * non-RECNUM dbp is if dbp is a secondary and its primary is
01972                  * DB_AM_RECNUM.
01973                  */
01974                 if (!F_ISSET(dbp, DB_AM_RECNUM) &&
01975                     (!F_ISSET(dbp, DB_AM_SECONDARY) ||
01976                     !F_ISSET(dbp->s_primary, DB_AM_RECNUM)))
01977                         goto err;
01978                 break;
01979         case DB_SET_RECNO:
01980                 if (!F_ISSET(dbp, DB_AM_RECNUM))
01981                         goto err;
01982                 break;
01983         default:
01984 err:            return (__db_ferr(dbenv, "DBcursor->get", 0));
01985         }
01986 
01987         /* Check for invalid key/data flags. */
01988         if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
01989                 return (ret);
01990         if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
01991                 return (ret);
01992 
01993         if (multi) {
01994                 if (!F_ISSET(data, DB_DBT_USERMEM)) {
01995                         __db_err(dbenv,
01996             "DB_MULTIPLE/DB_MULTIPLE_KEY require DB_DBT_USERMEM be set");
01997                         return (EINVAL);
01998                 }
01999                 if (F_ISSET(key, DB_DBT_PARTIAL) ||
02000                     F_ISSET(data, DB_DBT_PARTIAL)) {
02001                         __db_err(dbenv,
02002             "DB_MULTIPLE/DB_MULTIPLE_KEY do not support DB_DBT_PARTIAL");
02003                         return (EINVAL);
02004                 }
02005                 if (data->ulen < 1024 ||
02006                     data->ulen < dbp->pgsize || data->ulen % 1024 != 0) {
02007                         __db_err(dbenv, "%s%s",
02008                             "DB_MULTIPLE/DB_MULTIPLE_KEY buffers must be ",
02009                             "aligned, at least page size and multiples of 1KB");
02010                         return (EINVAL);
02011                 }
02012         }
02013 
02014         /*
02015          * The cursor must be initialized for DB_CURRENT, DB_GET_RECNO and
02016          * DB_NEXT_DUP.  Return EINVAL for an invalid cursor, otherwise 0.
02017          */
02018         if (!IS_INITIALIZED(dbc) && (flags == DB_CURRENT ||
02019             flags == DB_GET_RECNO || flags == DB_NEXT_DUP))
02020                 return (__db_curinval(dbenv));
02021 
02022         /* Check for consistent transaction usage. */
02023         if (LF_ISSET(DB_RMW) &&
02024             (ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0)
02025                 return (ret);
02026 
02027         return (0);
02028 }
02029 
02030 /*
02031  * __db_secondary_close_pp --
02032  *      DB->close for secondaries
02033  *
02034  * PUBLIC: int __db_secondary_close_pp __P((DB *, u_int32_t));
02035  */
02036 int
02037 __db_secondary_close_pp(dbp, flags)
02038         DB *dbp;
02039         u_int32_t flags;
02040 {
02041         DB_ENV *dbenv;
02042         DB_THREAD_INFO *ip;
02043         int handle_check, ret, t_ret;
02044 
02045         dbenv = dbp->dbenv;
02046         ret = 0;
02047 
02048         PANIC_CHECK(dbenv);
02049 
02050         /*
02051          * As a DB handle destructor, we can't fail.
02052          *
02053          * !!!
02054          * The actual argument checking is simple, do it inline, outside of
02055          * the replication block.
02056          */
02057         if (flags != 0 && flags != DB_NOSYNC)
02058                 ret = __db_ferr(dbenv, "DB->close", 0);
02059 
02060         ENV_ENTER(dbenv, ip);
02061 
02062         /* Check for replication block. */
02063         handle_check = IS_ENV_REPLICATED(dbenv);
02064         if (handle_check && (t_ret = __db_rep_enter(dbp, 0, 0, 0)) != 0) {
02065                 handle_check = 0;
02066                 if (ret == 0)
02067                         ret = t_ret;
02068         }
02069 
02070         if ((t_ret = __db_secondary_close(dbp, flags)) != 0 && ret == 0)
02071                 ret = t_ret;
02072 
02073         /* Release replication block. */
02074         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
02075                 ret = t_ret;
02076 
02077         ENV_LEAVE(dbenv, ip);
02078         return (ret);
02079 }
02080 
02081 /*
02082  * __db_c_pget_pp --
02083  *      DBC->c_pget pre/post processing.
02084  *
02085  * PUBLIC: int __db_c_pget_pp __P((DBC *, DBT *, DBT *, DBT *, u_int32_t));
02086  */
02087 int
02088 __db_c_pget_pp(dbc, skey, pkey, data, flags)
02089         DBC *dbc;
02090         DBT *skey, *pkey, *data;
02091         u_int32_t flags;
02092 {
02093         DB *dbp;
02094         DB_ENV *dbenv;
02095         DB_THREAD_INFO *ip;
02096         int ret;
02097 
02098         dbp = dbc->dbp;
02099         dbenv = dbp->dbenv;
02100 
02101         PANIC_CHECK(dbenv);
02102 
02103         if ((ret = __db_c_pget_arg(dbc, pkey, flags)) != 0 ||
02104             (ret = __db_c_get_arg(dbc, skey, data, flags)) != 0)
02105                 return (ret);
02106 
02107         ENV_ENTER(dbenv, ip);
02108 
02109         ret = __db_c_pget(dbc, skey, pkey, data, flags);
02110 
02111         ENV_LEAVE(dbenv, ip);
02112         return (ret);
02113 }
02114 
02115 /*
02116  * __db_c_pget_arg --
02117  *      Check DBC->pget arguments.
02118  */
02119 static int
02120 __db_c_pget_arg(dbc, pkey, flags)
02121         DBC *dbc;
02122         DBT *pkey;
02123         u_int32_t flags;
02124 {
02125         DB *dbp;
02126         DB_ENV *dbenv;
02127         int ret;
02128 
02129         dbp = dbc->dbp;
02130         dbenv = dbp->dbenv;
02131 
02132         if (!F_ISSET(dbp, DB_AM_SECONDARY)) {
02133                 __db_err(dbenv,
02134                     "DBcursor->pget may only be used on secondary indices");
02135                 return (EINVAL);
02136         }
02137 
02138         if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
02139                 __db_err(dbenv,
02140         "DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices");
02141                 return (EINVAL);
02142         }
02143 
02144         switch (LF_ISSET(~DB_RMW)) {
02145         case DB_CONSUME:
02146         case DB_CONSUME_WAIT:
02147                 /* These flags make no sense on a secondary index. */
02148                 return (__db_ferr(dbenv, "DBcursor->pget", 0));
02149         case DB_GET_BOTH:
02150                 /* DB_GET_BOTH is "get both the primary and the secondary". */
02151                 if (pkey == NULL) {
02152                         __db_err(dbenv,
02153                     "DB_GET_BOTH requires both a secondary and a primary key");
02154                         return (EINVAL);
02155                 }
02156                 break;
02157         default:
02158                 /* __db_c_get_arg will catch the rest. */
02159                 break;
02160         }
02161 
02162         /*
02163          * We allow the pkey field to be NULL, so that we can make the
02164          * two-DBT get calls into wrappers for the three-DBT ones.
02165          */
02166         if (pkey != NULL &&
02167             (ret = __dbt_ferr(dbp, "primary key", pkey, 0)) != 0)
02168                 return (ret);
02169 
02170         /* But the pkey field can't be NULL if we're doing a DB_GET_BOTH. */
02171         if (pkey == NULL && (flags & DB_OPFLAGS_MASK) == DB_GET_BOTH) {
02172                 __db_err(dbenv,
02173                     "DB_GET_BOTH on a secondary index requires a primary key");
02174                 return (EINVAL);
02175         }
02176         return (0);
02177 }
02178 
02179 /*
02180  * __db_c_put_pp --
02181  *      DBC->put pre/post processing.
02182  *
02183  * PUBLIC: int __db_c_put_pp __P((DBC *, DBT *, DBT *, u_int32_t));
02184  */
02185 int
02186 __db_c_put_pp(dbc, key, data, flags)
02187         DBC *dbc;
02188         DBT *key, *data;
02189         u_int32_t flags;
02190 {
02191         DB *dbp;
02192         DB_ENV *dbenv;
02193         DB_THREAD_INFO *ip;
02194         int ret;
02195 
02196         dbp = dbc->dbp;
02197         dbenv = dbp->dbenv;
02198 
02199         PANIC_CHECK(dbenv);
02200 
02201         if ((ret = __db_c_put_arg(dbc, key, data, flags)) != 0)
02202                 return (ret);
02203 
02204         ENV_ENTER(dbenv, ip);
02205 
02206         /* Check for consistent transaction usage. */
02207         if ((ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0)
02208                 goto err;
02209 
02210         DEBUG_LWRITE(dbc, dbc->txn, "DBcursor->put",
02211             flags == DB_KEYFIRST || flags == DB_KEYLAST ||
02212             flags == DB_NODUPDATA || flags == DB_UPDATE_SECONDARY ?
02213             key : NULL, data, flags);
02214         ret =__db_c_put(dbc, key, data, flags);
02215 err:
02216         ENV_LEAVE(dbenv, ip);
02217         return (ret);
02218 }
02219 
02220 /*
02221  * __db_c_put_arg --
02222  *      Check DBC->put arguments.
02223  */
02224 static int
02225 __db_c_put_arg(dbc, key, data, flags)
02226         DBC *dbc;
02227         DBT *key, *data;
02228         u_int32_t flags;
02229 {
02230         DB *dbp;
02231         DB_ENV *dbenv;
02232         int key_flags, ret;
02233 
02234         dbp = dbc->dbp;
02235         dbenv = dbp->dbenv;
02236         key_flags = 0;
02237 
02238         /* Check for changes to a read-only tree. */
02239         if (DB_IS_READONLY(dbp))
02240                 return (__db_rdonly(dbenv, "DBcursor->put"));
02241 
02242         /* Check for puts on a secondary. */
02243         if (F_ISSET(dbp, DB_AM_SECONDARY)) {
02244                 if (flags == DB_UPDATE_SECONDARY)
02245                         flags = DB_KEYLAST;
02246                 else {
02247                         __db_err(dbenv,
02248                     "DBcursor->put forbidden on secondary indices");
02249                         return (EINVAL);
02250                 }
02251         }
02252 
02253         /* Check for invalid function flags. */
02254         switch (flags) {
02255         case DB_AFTER:
02256         case DB_BEFORE:
02257                 switch (dbp->type) {
02258                 case DB_BTREE:
02259                 case DB_HASH:           /* Only with unsorted duplicates. */
02260                         if (!F_ISSET(dbp, DB_AM_DUP))
02261                                 goto err;
02262                         if (dbp->dup_compare != NULL)
02263                                 goto err;
02264                         break;
02265                 case DB_QUEUE:          /* Not permitted. */
02266                         goto err;
02267                 case DB_RECNO:          /* Only with mutable record numbers. */
02268                         if (!F_ISSET(dbp, DB_AM_RENUMBER))
02269                                 goto err;
02270                         key_flags = 1;
02271                         break;
02272                 case DB_UNKNOWN:
02273                 default:
02274                         goto err;
02275                 }
02276                 break;
02277         case DB_CURRENT:
02278                 /*
02279                  * If there is a comparison function, doing a DB_CURRENT
02280                  * must not change the part of the data item that is used
02281                  * for the comparison.
02282                  */
02283                 break;
02284         case DB_NODUPDATA:
02285                 if (!F_ISSET(dbp, DB_AM_DUPSORT))
02286                         goto err;
02287                 /* FALLTHROUGH */
02288         case DB_KEYFIRST:
02289         case DB_KEYLAST:
02290                 key_flags = 1;
02291                 break;
02292         default:
02293 err:            return (__db_ferr(dbenv, "DBcursor->put", 0));
02294         }
02295 
02296         /* Check for invalid key/data flags. */
02297         if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
02298                 return (ret);
02299         if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
02300                 return (ret);
02301 
02302         /* Keys shouldn't have partial flags during a put. */
02303         if (F_ISSET(key, DB_DBT_PARTIAL))
02304                 return (__db_ferr(dbenv, "key DBT", 0));
02305 
02306         /*
02307          * The cursor must be initialized for anything other than DB_KEYFIRST
02308          * and DB_KEYLAST, return EINVAL for an invalid cursor, otherwise 0.
02309          */
02310         if (!IS_INITIALIZED(dbc) && flags != DB_KEYFIRST &&
02311             flags != DB_KEYLAST && flags != DB_NODUPDATA)
02312                 return (__db_curinval(dbenv));
02313 
02314         return (0);
02315 }
02316 
02317 /*
02318  * __dbt_ferr --
02319  *      Check a DBT for flag errors.
02320  */
02321 static int
02322 __dbt_ferr(dbp, name, dbt, check_thread)
02323         const DB *dbp;
02324         const char *name;
02325         const DBT *dbt;
02326         int check_thread;
02327 {
02328         DB_ENV *dbenv;
02329         int ret;
02330 
02331         dbenv = dbp->dbenv;
02332 
02333         /*
02334          * Check for invalid DBT flags.  We allow any of the flags to be
02335          * specified to any DB or DBcursor call so that applications can
02336          * set DB_DBT_MALLOC when retrieving a data item from a secondary
02337          * database and then specify that same DBT as a key to a primary
02338          * database, without having to clear flags.
02339          */
02340         if ((ret = __db_fchk(dbenv, name, dbt->flags, DB_DBT_APPMALLOC |
02341             DB_DBT_MALLOC | DB_DBT_DUPOK | DB_DBT_REALLOC | DB_DBT_USERMEM |
02342             DB_DBT_PARTIAL)) != 0)
02343                 return (ret);
02344         switch (F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) {
02345         case 0:
02346         case DB_DBT_MALLOC:
02347         case DB_DBT_REALLOC:
02348         case DB_DBT_USERMEM:
02349                 break;
02350         default:
02351                 return (__db_ferr(dbenv, name, 1));
02352         }
02353 
02354         if (check_thread && DB_IS_THREADED(dbp) &&
02355             !F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) {
02356                 __db_err(dbenv,
02357                     "DB_THREAD mandates memory allocation flag on DBT %s",
02358                     name);
02359                 return (EINVAL);
02360         }
02361         return (0);
02362 }
02363 
02364 /*
02365  * __db_curinval
02366  *      Report that a cursor is in an invalid state.
02367  */
02368 static int
02369 __db_curinval(dbenv)
02370         const DB_ENV *dbenv;
02371 {
02372         __db_err(dbenv,
02373             "Cursor position must be set before performing this operation");
02374         return (EINVAL);
02375 }
02376 
02377 /*
02378  * __db_txn_auto_init --
02379  *      Handle DB_AUTO_COMMIT initialization.
02380  *
02381  * PUBLIC: int __db_txn_auto_init __P((DB_ENV *, DB_TXN **));
02382  */
02383 int
02384 __db_txn_auto_init(dbenv, txnidp)
02385         DB_ENV *dbenv;
02386         DB_TXN **txnidp;
02387 {
02388         /*
02389          * Method calls where applications explicitly specify DB_AUTO_COMMIT
02390          * require additional validation: the DB_AUTO_COMMIT flag cannot be
02391          * specified if a transaction cookie is also specified, nor can the
02392          * flag be specified in a non-transactional environment.
02393          */
02394         if (*txnidp != NULL) {
02395                 __db_err(dbenv,
02396     "DB_AUTO_COMMIT may not be specified along with a transaction handle");
02397                 return (EINVAL);
02398         }
02399 
02400         if (!TXN_ON(dbenv)) {
02401                 __db_err(dbenv,
02402     "DB_AUTO_COMMIT may not be specified in non-transactional environment");
02403                 return (EINVAL);
02404         }
02405 
02406         /*
02407          * Our caller checked to see if replication is making a state change.
02408          * Don't call the user-level API (which would repeat that check).
02409          */
02410         return (__txn_begin(dbenv, NULL, txnidp, 0));
02411 }
02412 
02413 /*
02414  * __db_txn_auto_resolve --
02415  *      Resolve local transactions.
02416  *
02417  * PUBLIC: int __db_txn_auto_resolve __P((DB_ENV *, DB_TXN *, int, int));
02418  */
02419 int
02420 __db_txn_auto_resolve(dbenv, txn, nosync, ret)
02421         DB_ENV *dbenv;
02422         DB_TXN *txn;
02423         int nosync, ret;
02424 {
02425         int t_ret;
02426 
02427         /*
02428          * We're resolving a transaction for the user, and must decrement the
02429          * replication handle count.  Call the user-level API.
02430          */
02431         if (ret == 0)
02432                 return (__txn_commit(txn, nosync ? DB_TXN_NOSYNC : 0));
02433 
02434         if ((t_ret = __txn_abort(txn)) != 0)
02435                 return (__db_panic(dbenv, t_ret));
02436 
02437         return (ret);
02438 }

Generated on Sun Dec 25 12:14:20 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2