db_open.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:19k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: db_open.c,v 11.215 2002/08/15 15:27:52 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stddef.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #endif
  17. #include "db_int.h"
  18. #include "dbinc/db_page.h"
  19. #include "dbinc/db_shash.h"
  20. #include "dbinc/db_swap.h"
  21. #include "dbinc/btree.h"
  22. #include "dbinc/crypto.h"
  23. #include "dbinc/hmac.h"
  24. #include "dbinc/fop.h"
  25. #include "dbinc/hash.h"
  26. #include "dbinc/lock.h"
  27. #include "dbinc/log.h"
  28. #include "dbinc/qam.h"
  29. #include "dbinc/txn.h"
  30. static int __db_openchk __P((DB *,
  31.     DB_TXN *, const char *, const char *, DBTYPE, u_int32_t));
  32. /*
  33.  * __db_open --
  34.  * Main library interface to the DB access methods.
  35.  *
  36.  * PUBLIC: int __db_open __P((DB *, DB_TXN *,
  37.  * PUBLIC:     const char *, const char *, DBTYPE, u_int32_t, int));
  38.  */
  39. int
  40. __db_open(dbp, txn, name, subdb, type, flags, mode)
  41. DB *dbp;
  42. DB_TXN *txn;
  43. const char *name, *subdb;
  44. DBTYPE type;
  45. u_int32_t flags;
  46. int mode;
  47. {
  48. DB_ENV *dbenv;
  49. int remove_master, remove_me, ret, t_ret, txn_local;
  50. dbenv = dbp->dbenv;
  51. remove_me = remove_master = txn_local = 0;
  52. PANIC_CHECK(dbenv);
  53. if ((ret = __db_openchk(dbp, txn, name, subdb, type, flags)) != 0)
  54. return (ret);
  55. /*
  56.  * Create local transaction as necessary, check for consistent
  57.  * transaction usage.
  58.  */
  59. if (IS_AUTO_COMMIT(dbenv, txn, flags)) {
  60. if ((ret = __db_txn_auto(dbp, &txn)) != 0)
  61. return (ret);
  62. txn_local = 1;
  63. } else
  64. if (txn != NULL && !TXN_ON(dbenv))
  65. return (__db_not_txn_env(dbenv));
  66. /*
  67.  * If the environment was configured with threads, the DB handle
  68.  * must also be free-threaded, so we force the DB_THREAD flag on.
  69.  * (See SR #2033 for why this is a requirement--recovery needs
  70.  * to be able to grab a dbp using __db_fileid_to_dbp, and it has
  71.  * no way of knowing which dbp goes with which thread, so whichever
  72.  * one it finds has to be usable in any of them.)
  73.  */
  74. if (F_ISSET(dbenv, DB_ENV_THREAD))
  75. LF_SET(DB_THREAD);
  76. /* Convert any DB->open flags. */
  77. if (LF_ISSET(DB_RDONLY))
  78. F_SET(dbp, DB_AM_RDONLY);
  79. if (LF_ISSET(DB_DIRTY_READ))
  80. F_SET(dbp, DB_AM_DIRTY);
  81. /* Fill in the type. */
  82. dbp->type = type;
  83. /*
  84.  * If we're opening a subdatabase, we have to open (and potentially
  85.  * create) the main database, and then get (and potentially store)
  86.  * our base page number in that database.  Then, we can finally open
  87.  * the subdatabase.
  88.  */
  89. if ((ret = __db_dbopen(
  90.     dbp, txn, name, subdb, flags, mode, PGNO_BASE_MD)) != 0)
  91. goto err;
  92. /*
  93.  * You can open the database that describes the subdatabases in the
  94.  * rest of the file read-only.  The content of each key's data is
  95.  * unspecified and applications should never be adding new records
  96.  * or updating existing records.  However, during recovery, we need
  97.  * to open these databases R/W so we can redo/undo changes in them.
  98.  * Likewise, we need to open master databases read/write during
  99.  * rename and remove so we can be sure they're fully sync'ed, so
  100.  * we provide an override flag for the purpose.
  101.  */
  102. if (subdb == NULL && !IS_RECOVERING(dbenv) && !LF_ISSET(DB_RDONLY) &&
  103.     !LF_ISSET(DB_RDWRMASTER) && F_ISSET(dbp, DB_AM_SUBDB)) {
  104. __db_err(dbenv,
  105.     "files containing multiple databases may only be opened read-only");
  106. ret = EINVAL;
  107. goto err;
  108. }
  109. err: /* If we were successful, don't discard the file on close. */
  110. if (ret == 0)
  111. /* If we were successful, don't discard the file on close. */
  112. F_CLR(dbp, DB_AM_DISCARD | DB_AM_CREATED | DB_AM_CREATED_MSTR);
  113. else {
  114. /*
  115.  * If we are not transactional, we need to remove the
  116.  * databases/subdatabases.  If we are transactional, then
  117.  * the abort of the child transaction should take care of
  118.  * cleaning them up.
  119.  */
  120. remove_me = txn == NULL && F_ISSET(dbp, DB_AM_CREATED);
  121. remove_master = txn == NULL && F_ISSET(dbp, DB_AM_CREATED_MSTR);
  122. /*
  123.  * If we had an error, it may have happened before or after
  124.  * we actually logged the open.  If it happened before, then
  125.  * abort won't know anything about it and won't close or
  126.  * refresh the dbp, so we need to do it explicitly.
  127.  */
  128. (void)__db_refresh(dbp, txn, DB_NOSYNC);
  129. }
  130. /* Remove anyone we created. */
  131. if (remove_master || (subdb == NULL && remove_me))
  132. /* Remove file. */
  133. (void)dbenv->dbremove(dbenv, txn, name, NULL, 0);
  134. else if (remove_me)
  135. /* Remove subdatabase. */
  136. (void)dbenv->dbremove(dbenv, txn, name, subdb, 0);
  137. /* Commit for DB_AUTO_COMMIT. */
  138. if (txn_local) {
  139. if (ret == 0)
  140. ret = txn->commit(txn, 0);
  141. else
  142. if ((t_ret = txn->abort(txn)) != 0)
  143. ret = __db_panic(dbenv, t_ret);
  144. }
  145. return (ret);
  146. }
  147. /*
  148.  * __db_dbopen --
  149.  * Open a database.  This routine  gets called in three different ways.
  150.  * 1. It can be called to open a file/database.  In this case, subdb will
  151.  *    be NULL and meta_pgno will be PGNO_BASE_MD.
  152.  * 2. It can be called to open a subdatabase during normal operation.  In
  153.  *    this case, name and subname will both be non-NULL and meta_pgno will
  154.  *    be PGNO_BAS_MD (also PGNO_INVALID).
  155.  * 3. It can be called during recovery to open a subdatabase in which case
  156.  *    name will be non-NULL, subname mqy be NULL and meta-pgno will be
  157.  *    a valid pgno (i.e., not PGNO_BASE_MD).
  158.  *
  159.  * PUBLIC: int __db_dbopen __P((DB *, DB_TXN *,
  160.  * PUBLIC:     const char *, const char *, u_int32_t, int, db_pgno_t));
  161.  */
  162. int
  163. __db_dbopen(dbp, txn, name, subdb, flags, mode, meta_pgno)
  164. DB *dbp;
  165. DB_TXN *txn;
  166. const char *name, *subdb;
  167. u_int32_t flags;
  168. int mode;
  169. db_pgno_t meta_pgno;
  170. {
  171. DB_ENV *dbenv;
  172. int ret;
  173. u_int32_t id;
  174. dbenv = dbp->dbenv;
  175. id = TXN_INVALID;
  176. if (txn != NULL)
  177. F_SET(dbp, DB_AM_TXN);
  178. DB_TEST_RECOVERY(dbp, DB_TEST_PREOPEN, ret, name);
  179. /*
  180.  * If name is NULL, it's always a create, so make sure that we
  181.  * have a type specified.  It would be nice if this checking
  182.  * were done in __db_open where most of the interface checking
  183.  * is done, but this interface (__db_dbopen) is used by the
  184.  * recovery and limbo system, so we need to safeguard this
  185.  * interface as well.
  186.  */
  187. if (name == NULL) {
  188. F_SET(dbp, DB_AM_INMEM);
  189. if (dbp->type == DB_UNKNOWN) {
  190. __db_err(dbenv,
  191.     "DBTYPE of unknown without existing file");
  192. return (EINVAL);
  193. }
  194. if (dbp->pgsize == 0)
  195. dbp->pgsize = DB_DEF_IOSIZE;
  196. /*
  197.  * If the file is a temporary file and we're doing locking,
  198.  * then we have to create a unique file ID.  We can't use our
  199.  * normal dev/inode pair (or whatever this OS uses in place of
  200.  * dev/inode pairs) because no backing file will be created
  201.  * until the mpool cache is filled forcing the buffers to disk.
  202.  * Grab a random locker ID to use as a file ID.  The created
  203.  * ID must never match a potential real file ID -- we know it
  204.  * won't because real file IDs contain a time stamp after the
  205.  * dev/inode pair, and we're simply storing a 4-byte value.
  206.  *
  207.  * !!!
  208.  * Store the locker in the file id structure -- we can get it
  209.  * from there as necessary, and it saves having two copies.
  210.  */
  211. if (LOCKING_ON(dbenv) && (ret = dbenv->lock_id(dbenv,
  212.     (u_int32_t *)dbp->fileid)) != 0)
  213. return (ret);
  214. } else if (subdb == NULL && meta_pgno == PGNO_BASE_MD) {
  215. /* Open/create the underlying file.  Acquire locks. */
  216. if ((ret =
  217.     __fop_file_setup(dbp, txn, name, mode, flags, &id)) != 0)
  218. return (ret);
  219. } else {
  220. if ((ret = __fop_subdb_setup(dbp,
  221.     txn, name, subdb, mode, flags)) != 0)
  222. return (ret);
  223. meta_pgno = dbp->meta_pgno;
  224. }
  225. /*
  226.  * If we created the file, set the truncate flag for the mpool.  This
  227.  * isn't for anything we've done, it's protection against stupid user
  228.  * tricks: if the user deleted a file behind Berkeley DB's back, we
  229.  * may still have pages in the mpool that match the file's "unique" ID.
  230.  *
  231.  * Note that if we're opening a subdatabase, we don't want to set
  232.  * the TRUNCATE flag even if we just created the file--we already
  233.  * opened and updated the master using access method interfaces,
  234.  * so we don't want to get rid of any pages that are in the mpool.
  235.  * If we created the file when we opened the master, we already hit
  236.  * this check in a non-subdb context then.
  237.  */
  238. if (subdb == NULL && F_ISSET(dbp, DB_AM_CREATED))
  239. LF_SET(DB_TRUNCATE);
  240. /* Set up the underlying environment. */
  241. if ((ret = __db_dbenv_setup(dbp, txn, name, id, flags)) != 0)
  242. return (ret);
  243. /*
  244.  * Set the open flag.  We use it to mean that the dbp has gone
  245.  * through mpf setup, including dbreg_register.  Also, below,
  246.  * the underlying access method open functions may want to do
  247.  * things like acquire cursors, so the open flag has to be set
  248.  * before calling them.
  249.  */
  250. F_SET(dbp, DB_AM_OPEN_CALLED);
  251. /*
  252.  * For unnamed files, we need to actually create the file now
  253.  * that the mpool is open.
  254.  */
  255. if (name == NULL && (ret = __db_new_file(dbp, txn, NULL, NULL)) != 0)
  256. return (ret);
  257. switch (dbp->type) {
  258. case DB_BTREE:
  259. ret = __bam_open(dbp, txn, name, meta_pgno, flags);
  260. break;
  261. case DB_HASH:
  262. ret = __ham_open(dbp, txn, name, meta_pgno, flags);
  263. break;
  264. case DB_RECNO:
  265. ret = __ram_open(dbp, txn, name, meta_pgno, flags);
  266. break;
  267. case DB_QUEUE:
  268. ret = __qam_open(dbp, txn, name, meta_pgno, mode, flags);
  269. break;
  270. case DB_UNKNOWN:
  271. return (__db_unknown_type(dbenv, "__db_dbopen", dbp->type));
  272. }
  273. if (ret != 0)
  274. goto err;
  275. DB_TEST_RECOVERY(dbp, DB_TEST_POSTOPEN, ret, name);
  276. /*
  277.  * Unnamed files don't need handle locks, so we only have to check
  278.  * for a handle lock downgrade or lockevent in the case of named
  279.  * files.
  280.  */
  281. if (!F_ISSET(dbp, DB_AM_RECOVER) &&
  282.     name != NULL && LOCK_ISSET(dbp->handle_lock)) {
  283. if (txn != NULL) {
  284. ret = __txn_lockevent(dbenv,
  285.     txn, dbp, &dbp->handle_lock, dbp->lid);
  286. } else if (LOCKING_ON(dbenv))
  287. /* Trade write handle lock for read handle lock. */
  288. ret = __lock_downgrade(dbenv,
  289.     &dbp->handle_lock, DB_LOCK_READ, 0);
  290. }
  291. DB_TEST_RECOVERY_LABEL
  292. err:
  293. return (ret);
  294. }
  295. /*
  296.  * __db_new_file --
  297.  * Create a new database file.
  298.  *
  299.  * PUBLIC: int __db_new_file __P((DB *, DB_TXN *, DB_FH *, const char *));
  300.  */
  301. int
  302. __db_new_file(dbp, txn, fhp, name)
  303. DB *dbp;
  304. DB_TXN *txn;
  305. DB_FH *fhp;
  306. const char *name;
  307. {
  308. int ret;
  309. switch (dbp->type) {
  310. case DB_BTREE:
  311. case DB_RECNO:
  312. ret = __bam_new_file(dbp, txn, fhp, name);
  313. break;
  314. case DB_HASH:
  315. ret = __ham_new_file(dbp, txn, fhp, name);
  316. break;
  317. case DB_QUEUE:
  318. ret = __qam_new_file(dbp, txn, fhp, name);
  319. break;
  320. default:
  321. __db_err(dbp->dbenv,
  322.     "%s: Invalid type %d specified", name, dbp->type);
  323. ret = EINVAL;
  324. break;
  325. }
  326. DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, name);
  327. /* Sync the file in preparation for moving it into place. */
  328. if (ret == 0 && fhp != NULL)
  329. ret = __os_fsync(dbp->dbenv, fhp);
  330. DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name);
  331. DB_TEST_RECOVERY_LABEL
  332. return (ret);
  333. }
  334. /*
  335.  * __db_init_subdb --
  336.  * Initialize the dbp for a subdb.
  337.  *
  338.  * PUBLIC: int __db_init_subdb __P((DB *, DB *, const char *, DB_TXN *));
  339.  */
  340. int
  341. __db_init_subdb(mdbp, dbp, name, txn)
  342. DB *mdbp, *dbp;
  343. const char *name;
  344. DB_TXN *txn;
  345. {
  346. DBMETA *meta;
  347. DB_MPOOLFILE *mpf;
  348. int ret, t_ret;
  349. ret = 0;
  350. if (!F_ISSET(dbp, DB_AM_CREATED)) {
  351. /* Subdb exists; read meta-data page and initialize. */
  352. mpf = mdbp->mpf;
  353. if  ((ret = mpf->get(mpf, &dbp->meta_pgno, 0, &meta)) != 0)
  354. goto err;
  355. ret = __db_meta_setup(mdbp->dbenv, dbp, name, meta, 0, 0);
  356. if ((t_ret = mpf->put(mpf, meta, 0)) != 0 && ret == 0)
  357. ret = t_ret;
  358. /*
  359.  * If __db_meta_setup found that the meta-page hadn't
  360.  * been written out during recovery, we can just return.
  361.  */
  362. if (ret == ENOENT)
  363. ret = 0;
  364. goto err;
  365. }
  366. /* Handle the create case here. */
  367. switch (dbp->type) {
  368. case DB_BTREE:
  369. case DB_RECNO:
  370. ret = __bam_new_subdb(mdbp, dbp, txn);
  371. break;
  372. case DB_HASH:
  373. ret = __ham_new_subdb(mdbp, dbp, txn);
  374. break;
  375. case DB_QUEUE:
  376. ret = EINVAL;
  377. break;
  378. default:
  379. __db_err(dbp->dbenv,
  380.     "Invalid subdatabase type %d specified", dbp->type);
  381. return (EINVAL);
  382. }
  383. err: return (ret);
  384. }
  385. /*
  386.  * __db_chk_meta --
  387.  * Take a buffer containing a meta-data page and check it for a checksum
  388.  * (and verify the checksum if necessary) and possibly decrypt it.
  389.  *
  390.  * Return 0 on success, >0 (errno) on error, -1 on checksum mismatch.
  391.  *
  392.  * PUBLIC: int __db_chk_meta __P((DB_ENV *, DB *, DBMETA *, int));
  393.  */
  394. int
  395. __db_chk_meta(dbenv, dbp, meta, do_metachk)
  396. DB_ENV *dbenv;
  397. DB *dbp;
  398. DBMETA *meta;
  399. int do_metachk;
  400. {
  401. int is_hmac, ret;
  402. u_int8_t *chksum;
  403. ret = 0;
  404. if (FLD_ISSET(meta->metaflags, DBMETA_CHKSUM)) {
  405. if (dbp != NULL)
  406. F_SET(dbp, DB_AM_CHKSUM);
  407. is_hmac = meta->encrypt_alg == 0 ? 0 : 1;
  408. chksum = ((BTMETA *)meta)->chksum;
  409. if (do_metachk && ((ret = __db_check_chksum(dbenv,
  410.     (DB_CIPHER *)dbenv->crypto_handle, chksum, meta,
  411.     DBMETASIZE, is_hmac)) != 0))
  412. return (ret);
  413. }
  414. #ifdef HAVE_CRYPTO
  415. ret = __crypto_decrypt_meta(dbenv, dbp, (u_int8_t *)meta, do_metachk);
  416. #endif
  417. return (ret);
  418. }
  419. /*
  420.  * __db_meta_setup --
  421.  *
  422.  * Take a buffer containing a meta-data page and figure out if it's
  423.  * valid, and if so, initialize the dbp from the meta-data page.
  424.  *
  425.  * PUBLIC: int __db_meta_setup __P((DB_ENV *,
  426.  * PUBLIC:     DB *, const char *, DBMETA *, u_int32_t, int));
  427.  */
  428. int
  429. __db_meta_setup(dbenv, dbp, name, meta, oflags, do_metachk)
  430. DB_ENV *dbenv;
  431. DB *dbp;
  432. const char *name;
  433. DBMETA *meta;
  434. u_int32_t oflags;
  435. int do_metachk;
  436. {
  437. u_int32_t flags, magic;
  438. int ret;
  439. ret = 0;
  440. /*
  441.  * Figure out what access method we're dealing with, and then
  442.  * call access method specific code to check error conditions
  443.  * based on conflicts between the found file and application
  444.  * arguments.  A found file overrides some user information --
  445.  * we don't consider it an error, for example, if the user set
  446.  * an expected byte order and the found file doesn't match it.
  447.  */
  448. F_CLR(dbp, DB_AM_SWAP);
  449. magic = meta->magic;
  450. swap_retry:
  451. switch (magic) {
  452. case DB_BTREEMAGIC:
  453. case DB_HASHMAGIC:
  454. case DB_QAMMAGIC:
  455. case DB_RENAMEMAGIC:
  456. break;
  457. case 0:
  458. /*
  459.  * The only time this should be 0 is if we're in the
  460.  * midst of opening a subdb during recovery and that
  461.  * subdatabase had its meta-data page allocated, but
  462.  * not yet initialized.
  463.  */
  464. if (F_ISSET(dbp, DB_AM_SUBDB) && ((IS_RECOVERING(dbenv) &&
  465.     F_ISSET((DB_LOG *) dbenv->lg_handle, DBLOG_FORCE_OPEN)) ||
  466.     meta->pgno != PGNO_INVALID))
  467. return (ENOENT);
  468. goto bad_format;
  469. default:
  470. if (F_ISSET(dbp, DB_AM_SWAP))
  471. goto bad_format;
  472. M_32_SWAP(magic);
  473. F_SET(dbp, DB_AM_SWAP);
  474. goto swap_retry;
  475. }
  476. /*
  477.  * We can only check the meta page if we are sure we have a meta page.
  478.  * If it is random data, then this check can fail.  So only now can we
  479.  * checksum and decrypt.  Don't distinguish between configuration and
  480.  * checksum match errors here, because we haven't opened the database
  481.  * and even a checksum error isn't a reason to panic the environment.
  482.  */
  483. if ((ret = __db_chk_meta(dbenv, dbp, meta, do_metachk)) != 0) {
  484. if (ret == -1)
  485. __db_err(dbenv,
  486.     "%s: metadata page checksum error", name);
  487. goto bad_format;
  488. }
  489. switch (magic) {
  490. case DB_BTREEMAGIC:
  491. flags = meta->flags;
  492. if (F_ISSET(dbp, DB_AM_SWAP))
  493. M_32_SWAP(flags);
  494. if (LF_ISSET(BTM_RECNO))
  495. dbp->type = DB_RECNO;
  496. else
  497. dbp->type = DB_BTREE;
  498. if ((oflags & DB_TRUNCATE) == 0 && (ret =
  499.     __bam_metachk(dbp, name, (BTMETA *)meta)) != 0)
  500. return (ret);
  501. break;
  502. case DB_HASHMAGIC:
  503. dbp->type = DB_HASH;
  504. if ((oflags & DB_TRUNCATE) == 0 && (ret =
  505.     __ham_metachk(dbp, name, (HMETA *)meta)) != 0)
  506. return (ret);
  507. break;
  508. case DB_QAMMAGIC:
  509. dbp->type = DB_QUEUE;
  510. if ((oflags & DB_TRUNCATE) == 0 && (ret =
  511.     __qam_metachk(dbp, name, (QMETA *)meta)) != 0)
  512. return (ret);
  513. break;
  514. case DB_RENAMEMAGIC:
  515. F_SET(dbp, DB_AM_IN_RENAME);
  516. break;
  517. }
  518. return (0);
  519. bad_format:
  520. __db_err(dbenv, "%s: unexpected file type or format", name);
  521. return (ret == 0 ? EINVAL : ret);
  522. }
  523. /*
  524.  * __db_openchk --
  525.  * Interface error checking for open calls.
  526.  */
  527. static int
  528. __db_openchk(dbp, txn, name, subdb, type, flags)
  529. DB *dbp;
  530. DB_TXN *txn;
  531. const char *name, *subdb;
  532. DBTYPE type;
  533. u_int32_t flags;
  534. {
  535. DB_ENV *dbenv;
  536. int ret;
  537. u_int32_t ok_flags;
  538. dbenv = dbp->dbenv;
  539. /* Validate arguments. */
  540. #define OKFLAGS
  541.     (DB_AUTO_COMMIT | DB_CREATE | DB_DIRTY_READ | DB_EXCL |
  542.      DB_FCNTL_LOCKING | DB_NOMMAP | DB_RDONLY | DB_RDWRMASTER |
  543.      DB_THREAD | DB_TRUNCATE | DB_WRITEOPEN)
  544. if ((ret = __db_fchk(dbenv, "DB->open", flags, OKFLAGS)) != 0)
  545. return (ret);
  546. if (LF_ISSET(DB_EXCL) && !LF_ISSET(DB_CREATE))
  547. return (__db_ferr(dbenv, "DB->open", 1));
  548. if (LF_ISSET(DB_RDONLY) && LF_ISSET(DB_CREATE))
  549. return (__db_ferr(dbenv, "DB->open", 1));
  550. #ifdef HAVE_VXWORKS
  551. if (LF_ISSET(DB_TRUNCATE)) {
  552. __db_err(dbenv, "DB_TRUNCATE unsupported in VxWorks");
  553. return (__db_eopnotsup(dbenv));
  554. }
  555. #endif
  556. switch (type) {
  557. case DB_UNKNOWN:
  558. if (LF_ISSET(DB_CREATE|DB_TRUNCATE)) {
  559. __db_err(dbenv,
  560.     "%s: DB_UNKNOWN type specified with DB_CREATE or DB_TRUNCATE",
  561.     name);
  562. return (EINVAL);
  563. }
  564. ok_flags = 0;
  565. break;
  566. case DB_BTREE:
  567. ok_flags = DB_OK_BTREE;
  568. break;
  569. case DB_HASH:
  570. ok_flags = DB_OK_HASH;
  571. break;
  572. case DB_QUEUE:
  573. ok_flags = DB_OK_QUEUE;
  574. break;
  575. case DB_RECNO:
  576. ok_flags = DB_OK_RECNO;
  577. break;
  578. default:
  579. __db_err(dbenv, "unknown type: %lu", (u_long)type);
  580. return (EINVAL);
  581. }
  582. if (ok_flags)
  583. DB_ILLEGAL_METHOD(dbp, ok_flags);
  584. /* The environment may have been created, but never opened. */
  585. if (!F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_OPEN_CALLED)) {
  586. __db_err(dbenv, "environment not yet opened");
  587. return (EINVAL);
  588. }
  589. /*
  590.  * Historically, you could pass in an environment that didn't have a
  591.  * mpool, and DB would create a private one behind the scenes.  This
  592.  * no longer works.
  593.  */
  594. if (!F_ISSET(dbenv, DB_ENV_DBLOCAL) && !MPOOL_ON(dbenv)) {
  595. __db_err(dbenv, "environment did not include a memory pool");
  596. return (EINVAL);
  597. }
  598. /*
  599.  * You can't specify threads during DB->open if subsystems in the
  600.  * environment weren't configured with them.
  601.  */
  602. if (LF_ISSET(DB_THREAD) &&
  603.     !F_ISSET(dbenv, DB_ENV_DBLOCAL | DB_ENV_THREAD)) {
  604. __db_err(dbenv, "environment not created using DB_THREAD");
  605. return (EINVAL);
  606. }
  607. /* DB_TRUNCATE is not transaction recoverable. */
  608. if (LF_ISSET(DB_TRUNCATE) && txn != NULL) {
  609. __db_err(dbenv,
  610.     "DB_TRUNCATE illegal with transaction specified");
  611. return (EINVAL);
  612. }
  613. /* Subdatabase checks. */
  614. if (subdb != NULL) {
  615. /* Subdatabases must be created in named files. */
  616. if (name == NULL) {
  617. __db_err(dbenv,
  618.     "multiple databases cannot be created in temporary files");
  619. return (EINVAL);
  620. }
  621. /* Truncate is a physical file operation */
  622. if (LF_ISSET(DB_TRUNCATE)) {
  623. __db_err(dbenv,
  624.     "DB_TRUNCATE illegal with multiple databases");
  625. return (EINVAL);
  626. }
  627. /* QAM can't be done as a subdatabase. */
  628. if (type == DB_QUEUE) {
  629. __db_err(dbenv, "Queue databases must be one-per-file");
  630. return (EINVAL);
  631. }
  632. }
  633. return (0);
  634. }