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

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_iface.c,v 11.77 2002/08/08 03:57:47 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #endif
  14. #include "db_int.h"
  15. #include "dbinc/db_page.h"
  16. #include "dbinc/db_am.h"
  17. static int __db_curinval __P((const DB_ENV *));
  18. static int __db_fnl __P((const DB_ENV *, const char *));
  19. static int __db_rdonly __P((const DB_ENV *, const char *));
  20. static int __dbt_ferr __P((const DB *, const char *, const DBT *, int));
  21. /*
  22.  * A database should be required to be readonly if it's been explicitly
  23.  * specified as such or if we're a client in a replicated environment and
  24.  * we don't have the special "client-writer" designation.
  25.  */
  26. #define IS_READONLY(dbp)
  27.     (F_ISSET(dbp, DB_AM_RDONLY) ||
  28.     (F_ISSET((dbp)->dbenv, DB_ENV_REP_CLIENT) &&
  29.     !F_ISSET((dbp), DB_AM_CL_WRITER)))
  30. /*
  31.  * __db_cursorchk --
  32.  * Common cursor argument checking routine.
  33.  *
  34.  * PUBLIC: int __db_cursorchk __P((const DB *, u_int32_t));
  35.  */
  36. int
  37. __db_cursorchk(dbp, flags)
  38. const DB *dbp;
  39. u_int32_t flags;
  40. {
  41. /* DB_DIRTY_READ is the only valid bit-flag and requires locking. */
  42. if (LF_ISSET(DB_DIRTY_READ)) {
  43. if (!LOCKING_ON(dbp->dbenv))
  44. return (__db_fnl(dbp->dbenv, "DB->cursor"));
  45. LF_CLR(DB_DIRTY_READ);
  46. }
  47. /* Check for invalid function flags. */
  48. switch (flags) {
  49. case 0:
  50. break;
  51. case DB_WRITECURSOR:
  52. if (IS_READONLY(dbp))
  53. return (__db_rdonly(dbp->dbenv, "DB->cursor"));
  54. if (!CDB_LOCKING(dbp->dbenv))
  55. return (__db_ferr(dbp->dbenv, "DB->cursor", 0));
  56. break;
  57. case DB_WRITELOCK:
  58. if (IS_READONLY(dbp))
  59. return (__db_rdonly(dbp->dbenv, "DB->cursor"));
  60. break;
  61. default:
  62. return (__db_ferr(dbp->dbenv, "DB->cursor", 0));
  63. }
  64. return (0);
  65. }
  66. /*
  67.  * __db_ccountchk --
  68.  * Common cursor count argument checking routine.
  69.  *
  70.  * PUBLIC: int __db_ccountchk __P((const DB *, u_int32_t, int));
  71.  */
  72. int
  73. __db_ccountchk(dbp, flags, isvalid)
  74. const DB *dbp;
  75. u_int32_t flags;
  76. int isvalid;
  77. {
  78. /* Check for invalid function flags. */
  79. switch (flags) {
  80. case 0:
  81. break;
  82. default:
  83. return (__db_ferr(dbp->dbenv, "DBcursor->c_count", 0));
  84. }
  85. /*
  86.  * The cursor must be initialized, return EINVAL for an invalid cursor,
  87.  * otherwise 0.
  88.  */
  89. return (isvalid ? 0 : __db_curinval(dbp->dbenv));
  90. }
  91. /*
  92.  * __db_cdelchk --
  93.  * Common cursor delete argument checking routine.
  94.  *
  95.  * PUBLIC: int __db_cdelchk __P((const DB *, u_int32_t, int));
  96.  */
  97. int
  98. __db_cdelchk(dbp, flags, isvalid)
  99. const DB *dbp;
  100. u_int32_t flags;
  101. int isvalid;
  102. {
  103. /* Check for changes to a read-only tree. */
  104. if (IS_READONLY(dbp))
  105. return (__db_rdonly(dbp->dbenv, "c_del"));
  106. /* Check for invalid function flags. */
  107. switch (flags) {
  108. case 0:
  109. break;
  110. case DB_UPDATE_SECONDARY:
  111. DB_ASSERT(F_ISSET(dbp, DB_AM_SECONDARY));
  112. break;
  113. default:
  114. return (__db_ferr(dbp->dbenv, "DBcursor->c_del", 0));
  115. }
  116. /*
  117.  * The cursor must be initialized, return EINVAL for an invalid cursor,
  118.  * otherwise 0.
  119.  */
  120. return (isvalid ? 0 : __db_curinval(dbp->dbenv));
  121. }
  122. /*
  123.  * __db_cgetchk --
  124.  * Common cursor get argument checking routine.
  125.  *
  126.  * PUBLIC: int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int));
  127.  */
  128. int
  129. __db_cgetchk(dbp, key, data, flags, isvalid)
  130. const DB *dbp;
  131. DBT *key, *data;
  132. u_int32_t flags;
  133. int isvalid;
  134. {
  135. int dirty, multi, ret;
  136. /*
  137.  * Check for read-modify-write validity.  DB_RMW doesn't make sense
  138.  * with CDB cursors since if you're going to write the cursor, you
  139.  * had to create it with DB_WRITECURSOR.  Regardless, we check for
  140.  * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it.
  141.  * If this changes, confirm that DB does not itself set the DB_RMW
  142.  * flag in a path where CDB may have been configured.
  143.  */
  144. dirty = 0;
  145. if (LF_ISSET(DB_DIRTY_READ | DB_RMW)) {
  146. if (!LOCKING_ON(dbp->dbenv))
  147. return (__db_fnl(dbp->dbenv, "DBcursor->c_get"));
  148. if (LF_ISSET(DB_DIRTY_READ))
  149. dirty = 1;
  150. LF_CLR(DB_DIRTY_READ | DB_RMW);
  151. }
  152. multi = 0;
  153. if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
  154. multi = 1;
  155. if (LF_ISSET(DB_MULTIPLE) && LF_ISSET(DB_MULTIPLE_KEY))
  156. goto multi_err;
  157. LF_CLR(DB_MULTIPLE | DB_MULTIPLE_KEY);
  158. }
  159. /* Check for invalid function flags. */
  160. switch (flags) {
  161. case DB_CONSUME:
  162. case DB_CONSUME_WAIT:
  163. if (dirty) {
  164. __db_err(dbp->dbenv,
  165.     "DB_DIRTY_READ is not supported with DB_CONSUME or DB_CONSUME_WAIT");
  166. return (EINVAL);
  167. }
  168. if (dbp->type != DB_QUEUE)
  169. goto err;
  170. break;
  171. case DB_CURRENT:
  172. case DB_FIRST:
  173. case DB_GET_BOTH:
  174. case DB_GET_BOTH_RANGE:
  175. case DB_NEXT:
  176. case DB_NEXT_DUP:
  177. case DB_NEXT_NODUP:
  178. case DB_SET:
  179. case DB_SET_RANGE:
  180. break;
  181. case DB_LAST:
  182. case DB_PREV:
  183. case DB_PREV_NODUP:
  184. if (multi)
  185. multi_err: return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 1));
  186. break;
  187. case DB_GET_BOTHC:
  188. if (dbp->type == DB_QUEUE)
  189. goto err;
  190. break;
  191. case DB_GET_RECNO:
  192. /*
  193.  * The one situation in which this might be legal with a
  194.  * non-RECNUM dbp is if dbp is a secondary and its primary is
  195.  * DB_AM_RECNUM.
  196.  */
  197. if (!F_ISSET(dbp, DB_AM_RECNUM) &&
  198.     (!F_ISSET(dbp, DB_AM_SECONDARY) ||
  199.     !F_ISSET(dbp->s_primary, DB_AM_RECNUM)))
  200. goto err;
  201. break;
  202. case DB_SET_RECNO:
  203. if (!F_ISSET(dbp, DB_AM_RECNUM))
  204. goto err;
  205. break;
  206. default:
  207. err: return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0));
  208. }
  209. /* Check for invalid key/data flags. */
  210. if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
  211. return (ret);
  212. if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
  213. return (ret);
  214. if (multi && !F_ISSET(data, DB_DBT_USERMEM)) {
  215. __db_err(dbp->dbenv,
  216.     "DB_MULTIPLE(_KEY) requires that DB_DBT_USERMEM be set");
  217. return (EINVAL);
  218. }
  219. if (multi &&
  220.     (F_ISSET(key, DB_DBT_PARTIAL) || F_ISSET(data, DB_DBT_PARTIAL))) {
  221. __db_err(dbp->dbenv,
  222.     "DB_DBT_PARTIAL forbidden with DB_MULTIPLE(_KEY)");
  223. return (EINVAL);
  224. }
  225. /*
  226.  * The cursor must be initialized for DB_CURRENT, DB_GET_RECNO and
  227.  * DB_NEXT_DUP.  Return EINVAL for an invalid cursor, otherwise 0.
  228.  */
  229. if (isvalid || (flags != DB_CURRENT &&
  230.     flags != DB_GET_RECNO && flags != DB_NEXT_DUP))
  231. return (0);
  232. return (__db_curinval(dbp->dbenv));
  233. }
  234. /*
  235.  * __db_cputchk --
  236.  * Common cursor put argument checking routine.
  237.  *
  238.  * PUBLIC: int __db_cputchk __P((const DB *,
  239.  * PUBLIC:    const DBT *, DBT *, u_int32_t, int));
  240.  */
  241. int
  242. __db_cputchk(dbp, key, data, flags, isvalid)
  243. const DB *dbp;
  244. const DBT *key;
  245. DBT *data;
  246. u_int32_t flags;
  247. int isvalid;
  248. {
  249. int key_flags, ret;
  250. key_flags = 0;
  251. /* Check for changes to a read-only tree. */
  252. if (IS_READONLY(dbp))
  253. return (__db_rdonly(dbp->dbenv, "c_put"));
  254. /* Check for puts on a secondary. */
  255. if (F_ISSET(dbp, DB_AM_SECONDARY)) {
  256. if (flags == DB_UPDATE_SECONDARY)
  257. flags = DB_KEYLAST;
  258. else {
  259. __db_err(dbp->dbenv,
  260.     "DBcursor->c_put forbidden on secondary indices");
  261. return (EINVAL);
  262. }
  263. }
  264. /* Check for invalid function flags. */
  265. switch (flags) {
  266. case DB_AFTER:
  267. case DB_BEFORE:
  268. switch (dbp->type) {
  269. case DB_BTREE:
  270. case DB_HASH: /* Only with unsorted duplicates. */
  271. if (!F_ISSET(dbp, DB_AM_DUP))
  272. goto err;
  273. if (dbp->dup_compare != NULL)
  274. goto err;
  275. break;
  276. case DB_QUEUE: /* Not permitted. */
  277. goto err;
  278. case DB_RECNO: /* Only with mutable record numbers. */
  279. if (!F_ISSET(dbp, DB_AM_RENUMBER))
  280. goto err;
  281. key_flags = 1;
  282. break;
  283. default:
  284. goto err;
  285. }
  286. break;
  287. case DB_CURRENT:
  288. /*
  289.  * If there is a comparison function, doing a DB_CURRENT
  290.  * must not change the part of the data item that is used
  291.  * for the comparison.
  292.  */
  293. break;
  294. case DB_NODUPDATA:
  295. if (!F_ISSET(dbp, DB_AM_DUPSORT))
  296. goto err;
  297. /* FALLTHROUGH */
  298. case DB_KEYFIRST:
  299. case DB_KEYLAST:
  300. key_flags = 1;
  301. break;
  302. default:
  303. err: return (__db_ferr(dbp->dbenv, "DBcursor->c_put", 0));
  304. }
  305. /* Check for invalid key/data flags. */
  306. if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0)
  307. return (ret);
  308. if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
  309. return (ret);
  310. /*
  311.  * The cursor must be initialized for anything other than DB_KEYFIRST
  312.  * and DB_KEYLAST, return EINVAL for an invalid cursor, otherwise 0.
  313.  */
  314. if (isvalid || flags == DB_KEYFIRST ||
  315.     flags == DB_KEYLAST || flags == DB_NODUPDATA)
  316. return (0);
  317. return (__db_curinval(dbp->dbenv));
  318. }
  319. /*
  320.  * __db_pgetchk --
  321.  * DB->pget flag check.
  322.  *
  323.  * PUBLIC: int __db_pgetchk __P((const DB *, const DBT *, DBT *, DBT *,
  324.  * PUBLIC: u_int32_t));
  325.  */
  326. int
  327. __db_pgetchk(dbp, skey, pkey, data, flags)
  328. const DB *dbp;
  329. const DBT *skey;
  330. DBT *pkey, *data;
  331. u_int32_t flags;
  332. {
  333. int ret;
  334. u_int32_t save_flags;
  335. save_flags = flags;
  336. if (!F_ISSET(dbp, DB_AM_SECONDARY)) {
  337. __db_err(dbp->dbenv,
  338.     "DB->pget may only be used on secondary indices");
  339. return (EINVAL);
  340. }
  341. if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
  342. __db_err(dbp->dbenv,
  343. "DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices");
  344. return (EINVAL);
  345. }
  346. /* DB_CONSUME makes no sense on a secondary index. */
  347. LF_CLR(DB_RMW);
  348. switch (flags) {
  349. case DB_CONSUME:
  350. case DB_CONSUME_WAIT:
  351. return (__db_ferr(dbp->dbenv, "DB->pget", 0));
  352. default:
  353. /* __db_getchk will catch the rest. */
  354. break;
  355. }
  356. /*
  357.  * We allow the pkey field to be NULL, so that we can make the
  358.  * two-DBT get calls into wrappers for the three-DBT ones.
  359.  */
  360. if (pkey != NULL &&
  361.     (ret = __dbt_ferr(dbp, "primary key", pkey, 1)) != 0)
  362. return (ret);
  363. /* But the pkey field can't be NULL if we're doing a DB_GET_BOTH. */
  364. if (pkey == NULL && flags == DB_GET_BOTH) {
  365. __db_err(dbp->dbenv,
  366.     "DB_GET_BOTH on a secondary index requires a primary key");
  367. return (EINVAL);
  368. }
  369. return (__db_getchk(dbp, skey, data, save_flags));
  370. }
  371. /*
  372.  * __db_cpgetchk --
  373.  * Secondary-index cursor get argument checking routine.
  374.  *
  375.  * PUBLIC: int __db_cpgetchk __P((const DB *,
  376.  * PUBLIC:     DBT *, DBT *, DBT *, u_int32_t, int));
  377.  */
  378. int
  379. __db_cpgetchk(dbp, skey, pkey, data, flags, isvalid)
  380. const DB *dbp;
  381. DBT *skey, *pkey, *data;
  382. u_int32_t flags;
  383. int isvalid;
  384. {
  385. int ret;
  386. u_int32_t save_flags;
  387. save_flags = flags;
  388. if (!F_ISSET(dbp, DB_AM_SECONDARY)) {
  389. __db_err(dbp->dbenv,
  390.     "DBcursor->c_pget may only be used on secondary indices");
  391. return (EINVAL);
  392. }
  393. if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
  394. __db_err(dbp->dbenv,
  395. "DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices");
  396. return (EINVAL);
  397. }
  398. LF_CLR(DB_RMW);
  399. switch (flags) {
  400. case DB_CONSUME:
  401. case DB_CONSUME_WAIT:
  402. /* DB_CONSUME makes no sense on a secondary index. */
  403. return (__db_ferr(dbp->dbenv, "DBcursor->c_pget", 0));
  404. case DB_GET_BOTH:
  405. /* DB_GET_BOTH is "get both the primary and the secondary". */
  406. if (pkey == NULL) {
  407. __db_err(dbp->dbenv,
  408.     "DB_GET_BOTH requires both a secondary and a primary key");
  409. return (EINVAL);
  410. }
  411. break;
  412. default:
  413. /* __db_cgetchk will catch the rest. */
  414. break;
  415. }
  416. /*
  417.  * We allow the pkey field to be NULL, so that we can make the
  418.  * two-DBT get calls into wrappers for the three-DBT ones.
  419.  */
  420. if (pkey != NULL &&
  421.     (ret = __dbt_ferr(dbp, "primary key", pkey, 0)) != 0)
  422. return (ret);
  423. /* But the pkey field can't be NULL if we're doing a DB_GET_BOTH. */
  424. if (pkey == NULL && flags == DB_GET_BOTH) {
  425. __db_err(dbp->dbenv,
  426.     "DB_GET_BOTH on a secondary index requires a primary key");
  427. return (EINVAL);
  428. }
  429. return (__db_cgetchk(dbp, skey, data, save_flags, isvalid));
  430. }
  431. /*
  432.  * __db_delchk --
  433.  * Common delete argument checking routine.
  434.  *
  435.  * PUBLIC: int __db_delchk __P((const DB *, DBT *, u_int32_t));
  436.  */
  437. int
  438. __db_delchk(dbp, key, flags)
  439. const DB *dbp;
  440. DBT *key;
  441. u_int32_t flags;
  442. {
  443. COMPQUIET(key, NULL);
  444. /* Check for changes to a read-only tree. */
  445. if (IS_READONLY(dbp))
  446. return (__db_rdonly(dbp->dbenv, "delete"));
  447. /* Check for invalid function flags. */
  448. LF_CLR(DB_AUTO_COMMIT);
  449. switch (flags) {
  450. case 0:
  451. break;
  452. default:
  453. return (__db_ferr(dbp->dbenv, "DB->del", 0));
  454. }
  455. return (0);
  456. }
  457. /*
  458.  * __db_getchk --
  459.  * Common get argument checking routine.
  460.  *
  461.  * PUBLIC: int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t));
  462.  */
  463. int
  464. __db_getchk(dbp, key, data, flags)
  465. const DB *dbp;
  466. const DBT *key;
  467. DBT *data;
  468. u_int32_t flags;
  469. {
  470. int dirty, multi, ret;
  471. /*
  472.  * Check for read-modify-write validity.  DB_RMW doesn't make sense
  473.  * with CDB cursors since if you're going to write the cursor, you
  474.  * had to create it with DB_WRITECURSOR.  Regardless, we check for
  475.  * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it.
  476.  * If this changes, confirm that DB does not itself set the DB_RMW
  477.  * flag in a path where CDB may have been configured.
  478.  */
  479. dirty = 0;
  480. if (LF_ISSET(DB_DIRTY_READ | DB_RMW)) {
  481. if (!LOCKING_ON(dbp->dbenv))
  482. return (__db_fnl(dbp->dbenv, "DB->get"));
  483. if (LF_ISSET(DB_DIRTY_READ))
  484. dirty = 1;
  485. LF_CLR(DB_DIRTY_READ | DB_RMW);
  486. }
  487. multi = 0;
  488. if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) {
  489. if (LF_ISSET(DB_MULTIPLE_KEY))
  490. goto multi_err;
  491. multi = LF_ISSET(DB_MULTIPLE) ? 1 : 0;
  492. LF_CLR(DB_MULTIPLE);
  493. }
  494. /* Check for invalid function flags. */
  495. switch (flags) {
  496. case 0:
  497. case DB_GET_BOTH:
  498. break;
  499. case DB_SET_RECNO:
  500. if (!F_ISSET(dbp, DB_AM_RECNUM))
  501. goto err;
  502. break;
  503. case DB_CONSUME:
  504. case DB_CONSUME_WAIT:
  505. if (dirty) {
  506. __db_err(dbp->dbenv,
  507.     "DB_DIRTY_READ is not supported with DB_CONSUME or DB_CONSUME_WAIT");
  508. return (EINVAL);
  509. }
  510. if (multi)
  511. multi_err: return (__db_ferr(dbp->dbenv, "DB->get", 1));
  512. if (dbp->type == DB_QUEUE)
  513. break;
  514. /* FALLTHROUGH */
  515. default:
  516. err: return (__db_ferr(dbp->dbenv, "DB->get", 0));
  517. }
  518. /*
  519.  * Check for invalid key/data flags.
  520.  *
  521.  * XXX: Dave Krinsky
  522.  * Remember to modify this when we fix the flag-returning problem.
  523.  */
  524. if ((ret = __dbt_ferr(dbp, "key", key, flags == DB_SET_RECNO)) != 0)
  525. return (ret);
  526. if ((ret = __dbt_ferr(dbp, "data", data, 1)) != 0)
  527. return (ret);
  528. if (multi && !F_ISSET(data, DB_DBT_USERMEM)) {
  529. __db_err(dbp->dbenv,
  530.     "DB_MULTIPLE requires that DB_DBT_USERMEM be set");
  531. return (EINVAL);
  532. }
  533. if (multi &&
  534.     (F_ISSET(key, DB_DBT_PARTIAL) || F_ISSET(data, DB_DBT_PARTIAL))) {
  535. __db_err(dbp->dbenv,
  536.     "DB_DBT_PARTIAL forbidden with DB_MULTIPLE(_KEY)");
  537. return (EINVAL);
  538. }
  539. return (0);
  540. }
  541. /*
  542.  * __db_joinchk --
  543.  * Common join argument checking routine.
  544.  *
  545.  * PUBLIC: int __db_joinchk __P((const DB *, DBC * const *, u_int32_t));
  546.  */
  547. int
  548. __db_joinchk(dbp, curslist, flags)
  549. const DB *dbp;
  550. DBC * const *curslist;
  551. u_int32_t flags;
  552. {
  553. DB_TXN *txn;
  554. int i;
  555. switch (flags) {
  556. case 0:
  557. case DB_JOIN_NOSORT:
  558. break;
  559. default:
  560. return (__db_ferr(dbp->dbenv, "DB->join", 0));
  561. }
  562. if (curslist == NULL || curslist[0] == NULL) {
  563. __db_err(dbp->dbenv,
  564.     "At least one secondary cursor must be specified to DB->join");
  565. return (EINVAL);
  566. }
  567. txn = curslist[0]->txn;
  568. for (i = 1; curslist[i] != NULL; i++)
  569. if (curslist[i]->txn != txn) {
  570. __db_err(dbp->dbenv,
  571.     "All secondary cursors must share the same transaction");
  572. return (EINVAL);
  573. }
  574. return (0);
  575. }
  576. /*
  577.  * __db_joingetchk --
  578.  * Common join_get argument checking routine.
  579.  *
  580.  * PUBLIC: int __db_joingetchk __P((const DB *, DBT *, u_int32_t));
  581.  */
  582. int
  583. __db_joingetchk(dbp, key, flags)
  584. const DB *dbp;
  585. DBT *key;
  586. u_int32_t flags;
  587. {
  588. if (LF_ISSET(DB_DIRTY_READ | DB_RMW)) {
  589. if (!LOCKING_ON(dbp->dbenv))
  590. return (__db_fnl(dbp->dbenv, "DBcursor->c_get"));
  591. LF_CLR(DB_DIRTY_READ | DB_RMW);
  592. }
  593. switch (flags) {
  594. case 0:
  595. case DB_JOIN_ITEM:
  596. break;
  597. default:
  598. return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0));
  599. }
  600. /*
  601.  * A partial get of the key of a join cursor don't make much sense;
  602.  * the entire key is necessary to query the primary database
  603.  * and find the datum, and so regardless of the size of the key
  604.  * it would not be a performance improvement.  Since it would require
  605.  * special handling, we simply disallow it.
  606.  *
  607.  * A partial get of the data, however, potentially makes sense (if
  608.  * all possible data are a predictable large structure, for instance)
  609.  * and causes us no headaches, so we permit it.
  610.  */
  611. if (F_ISSET(key, DB_DBT_PARTIAL)) {
  612. __db_err(dbp->dbenv,
  613.     "DB_DBT_PARTIAL may not be set on key during join_get");
  614. return (EINVAL);
  615. }
  616. return (0);
  617. }
  618. /*
  619.  * __db_putchk --
  620.  * Common put argument checking routine.
  621.  *
  622.  * PUBLIC: int __db_putchk
  623.  * PUBLIC:    __P((const DB *, DBT *, const DBT *, u_int32_t, int));
  624.  */
  625. int
  626. __db_putchk(dbp, key, data, flags, isdup)
  627. const DB *dbp;
  628. DBT *key;
  629. const DBT *data;
  630. u_int32_t flags;
  631. int isdup;
  632. {
  633. int ret, returnkey;
  634. returnkey = 0;
  635. /* Check for changes to a read-only tree. */
  636. if (IS_READONLY(dbp))
  637. return (__db_rdonly(dbp->dbenv, "put"));
  638. /* Check for puts on a secondary. */
  639. if (F_ISSET(dbp, DB_AM_SECONDARY)) {
  640. __db_err(dbp->dbenv, "DB->put forbidden on secondary indices");
  641. return (EINVAL);
  642. }
  643. /* Check for invalid function flags. */
  644. LF_CLR(DB_AUTO_COMMIT);
  645. switch (flags) {
  646. case 0:
  647. case DB_NOOVERWRITE:
  648. break;
  649. case DB_APPEND:
  650. if (dbp->type != DB_RECNO && dbp->type != DB_QUEUE)
  651. goto err;
  652. returnkey = 1;
  653. break;
  654. case DB_NODUPDATA:
  655. if (F_ISSET(dbp, DB_AM_DUPSORT))
  656. break;
  657. /* FALLTHROUGH */
  658. default:
  659. err: return (__db_ferr(dbp->dbenv, "DB->put", 0));
  660. }
  661. /* Check for invalid key/data flags. */
  662. if ((ret = __dbt_ferr(dbp, "key", key, returnkey)) != 0)
  663. return (ret);
  664. if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0)
  665. return (ret);
  666. /* Check for partial puts in the presence of duplicates. */
  667. if (isdup && F_ISSET(data, DB_DBT_PARTIAL)) {
  668. __db_err(dbp->dbenv,
  669. "a partial put in the presence of duplicates requires a cursor operation");
  670. return (EINVAL);
  671. }
  672. return (0);
  673. }
  674. /*
  675.  * __db_statchk --
  676.  * Common stat argument checking routine.
  677.  *
  678.  * PUBLIC: int __db_statchk __P((const DB *, u_int32_t));
  679.  */
  680. int
  681. __db_statchk(dbp, flags)
  682. const DB *dbp;
  683. u_int32_t flags;
  684. {
  685. /* Check for invalid function flags. */
  686. switch (flags) {
  687. case 0:
  688. case DB_FAST_STAT:
  689. case DB_CACHED_COUNTS: /* Deprecated and undocumented. */
  690. break;
  691. case DB_RECORDCOUNT: /* Deprecated and undocumented. */
  692. if (dbp->type == DB_RECNO)
  693. break;
  694. if (dbp->type == DB_BTREE && F_ISSET(dbp, DB_AM_RECNUM))
  695. break;
  696. goto err;
  697. default:
  698. err: return (__db_ferr(dbp->dbenv, "DB->stat", 0));
  699. }
  700. return (0);
  701. }
  702. /*
  703.  * __db_syncchk --
  704.  * Common sync argument checking routine.
  705.  *
  706.  * PUBLIC: int __db_syncchk __P((const DB *, u_int32_t));
  707.  */
  708. int
  709. __db_syncchk(dbp, flags)
  710. const DB *dbp;
  711. u_int32_t flags;
  712. {
  713. /* Check for invalid function flags. */
  714. switch (flags) {
  715. case 0:
  716. break;
  717. default:
  718. return (__db_ferr(dbp->dbenv, "DB->sync", 0));
  719. }
  720. return (0);
  721. }
  722. /*
  723.  * __dbt_ferr --
  724.  * Check a DBT for flag errors.
  725.  */
  726. static int
  727. __dbt_ferr(dbp, name, dbt, check_thread)
  728. const DB *dbp;
  729. const char *name;
  730. const DBT *dbt;
  731. int check_thread;
  732. {
  733. DB_ENV *dbenv;
  734. int ret;
  735. dbenv = dbp->dbenv;
  736. /*
  737.  * Check for invalid DBT flags.  We allow any of the flags to be
  738.  * specified to any DB or DBcursor call so that applications can
  739.  * set DB_DBT_MALLOC when retrieving a data item from a secondary
  740.  * database and then specify that same DBT as a key to a primary
  741.  * database, without having to clear flags.
  742.  */
  743. if ((ret = __db_fchk(dbenv, name, dbt->flags, DB_DBT_APPMALLOC |
  744.     DB_DBT_MALLOC | DB_DBT_DUPOK | DB_DBT_REALLOC | DB_DBT_USERMEM |
  745.     DB_DBT_PARTIAL)) != 0)
  746. return (ret);
  747. switch (F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) {
  748. case 0:
  749. case DB_DBT_MALLOC:
  750. case DB_DBT_REALLOC:
  751. case DB_DBT_USERMEM:
  752. break;
  753. default:
  754. return (__db_ferr(dbenv, name, 1));
  755. }
  756. if (check_thread && DB_IS_THREADED(dbp) &&
  757.     !F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) {
  758. __db_err(dbenv,
  759.     "DB_THREAD mandates memory allocation flag on DBT %s",
  760.     name);
  761. return (EINVAL);
  762. }
  763. return (0);
  764. }
  765. /*
  766.  * __db_rdonly --
  767.  * Common readonly message.
  768.  */
  769. static int
  770. __db_rdonly(dbenv, name)
  771. const DB_ENV *dbenv;
  772. const char *name;
  773. {
  774. __db_err(dbenv, "%s: attempt to modify a read-only tree", name);
  775. return (EACCES);
  776. }
  777. /*
  778.  * __db_fnl --
  779.  * Common flag-needs-locking message.
  780.  */
  781. static int
  782. __db_fnl(dbenv, name)
  783. const DB_ENV *dbenv;
  784. const char *name;
  785. {
  786. __db_err(dbenv,
  787.     "%s: the DB_DIRTY_READ and DB_RMW flags require locking", name);
  788. return (EINVAL);
  789. }
  790. /*
  791.  * __db_curinval
  792.  * Report that a cursor is in an invalid state.
  793.  */
  794. static int
  795. __db_curinval(dbenv)
  796. const DB_ENV *dbenv;
  797. {
  798. __db_err(dbenv,
  799.     "Cursor position must be set before performing this operation");
  800. return (EINVAL);
  801. }
  802. /*
  803.  * __db_secondary_corrupt --
  804.  * Report that a secondary index appears corrupt, as it has a record
  805.  * that does not correspond to a record in the primary.
  806.  *
  807.  * PUBLIC: int __db_secondary_corrupt __P((DB *));
  808.  */
  809. int
  810. __db_secondary_corrupt(dbp)
  811. DB *dbp;
  812. {
  813. __db_err(dbp->dbenv,
  814.     "Secondary index corrupt: item in secondary not found in primary");
  815. return (DB_SECONDARY_BAD);
  816. }
  817. /*
  818.  * __db_associatechk --
  819.  * Argument checking routine for DB->associate().
  820.  *
  821.  * PUBLIC: int __db_associatechk __P((DB *, DB *,
  822.  * PUBLIC:     int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t));
  823.  */
  824. int
  825. __db_associatechk(dbp, sdbp, callback, flags)
  826. DB *dbp, *sdbp;
  827. int (*callback) __P((DB *, const DBT *, const DBT *, DBT *));
  828. u_int32_t flags;
  829. {
  830. DB_ENV *dbenv;
  831. dbenv = dbp->dbenv;
  832. if (F_ISSET(sdbp, DB_AM_SECONDARY)) {
  833. __db_err(dbenv,
  834.     "Secondary index handles may not be re-associated");
  835. return (EINVAL);
  836. }
  837. if (F_ISSET(dbp, DB_AM_SECONDARY)) {
  838. __db_err(dbenv,
  839.     "Secondary indices may not be used as primary databases");
  840. return (EINVAL);
  841. }
  842. if (F_ISSET(dbp, DB_AM_DUP)) {
  843. __db_err(dbenv,
  844.     "Primary databases may not be configured with duplicates");
  845. return (EINVAL);
  846. }
  847. if (F_ISSET(dbp, DB_AM_RENUMBER)) {
  848. __db_err(dbenv,
  849.     "Renumbering recno databases may not be used as primary databases");
  850. return (EINVAL);
  851. }
  852. if (callback == NULL &&
  853.     (!F_ISSET(dbp, DB_AM_RDONLY) || !F_ISSET(sdbp, DB_AM_RDONLY))) {
  854. __db_err(dbenv,
  855.     "Callback function may be NULL only when database handles are read-only");
  856. return (EINVAL);
  857. }
  858. return (__db_fchk(dbenv,
  859.     "DB->associate", flags, DB_CREATE | DB_AUTO_COMMIT));
  860. }
  861. /*
  862.  * __db_txn_auto --
  863.  * Handle DB_AUTO_COMMIT initialization.
  864.  *
  865.  * PUBLIC: int __db_txn_auto __P((DB *, DB_TXN **));
  866.  */
  867. int
  868. __db_txn_auto(dbp, txnidp)
  869. DB *dbp;
  870. DB_TXN **txnidp;
  871. {
  872. DB_ENV *dbenv;
  873. dbenv = dbp->dbenv;
  874. if (*txnidp != NULL) {
  875. __db_err(dbenv,
  876.     "DB_AUTO_COMMIT may not be specified along with a transaction handle");
  877. return (EINVAL);
  878. }
  879. if (!TXN_ON(dbenv)) {
  880. __db_err(dbenv,
  881.     "DB_AUTO_COMMIT may not be specified in non-transactional environment");
  882. return (EINVAL);
  883. }
  884. return (dbenv->txn_begin(dbenv, NULL, txnidp, 0));
  885. }