db_join.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:21k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: db_join.c,v 11.31 2000/12/20 22:41:54 krinsky Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #endif
  16. #include "db_int.h"
  17. #include "db_page.h"
  18. #include "db_join.h"
  19. #include "db_am.h"
  20. #include "btree.h"
  21. static int __db_join_close __P((DBC *));
  22. static int __db_join_cmp __P((const void *, const void *));
  23. static int __db_join_del __P((DBC *, u_int32_t));
  24. static int __db_join_get __P((DBC *, DBT *, DBT *, u_int32_t));
  25. static int __db_join_getnext __P((DBC *, DBT *, DBT *, u_int32_t));
  26. static int __db_join_put __P((DBC *, DBT *, DBT *, u_int32_t));
  27. /*
  28.  * Check to see if the Nth secondary cursor of join cursor jc is pointing
  29.  * to a sorted duplicate set.
  30.  */
  31. #define SORTED_SET(jc, n)   ((jc)->j_curslist[(n)]->dbp->dup_compare != NULL)
  32. /*
  33.  * This is the duplicate-assisted join functionality.  Right now we're
  34.  * going to write it such that we return one item at a time, although
  35.  * I think we may need to optimize it to return them all at once.
  36.  * It should be easier to get it working this way, and I believe that
  37.  * changing it should be fairly straightforward.
  38.  *
  39.  * We optimize the join by sorting cursors from smallest to largest
  40.  * cardinality.  In most cases, this is indeed optimal.  However, if
  41.  * a cursor with large cardinality has very few data in common with the
  42.  * first cursor, it is possible that the join will be made faster by
  43.  * putting it earlier in the cursor list.  Since we have no way to detect
  44.  * cases like this, we simply provide a flag, DB_JOIN_NOSORT, which retains
  45.  * the sort order specified by the caller, who may know more about the
  46.  * structure of the data.
  47.  *
  48.  * The first cursor moves sequentially through the duplicate set while
  49.  * the others search explicitly for the duplicate in question.
  50.  *
  51.  */
  52. /*
  53.  * __db_join --
  54.  * This is the interface to the duplicate-assisted join functionality.
  55.  * In the same way that cursors mark a position in a database, a cursor
  56.  * can mark a position in a join.  While most cursors are created by the
  57.  * cursor method of a DB, join cursors are created through an explicit
  58.  * call to DB->join.
  59.  *
  60.  * The curslist is an array of existing, intialized cursors and primary
  61.  * is the DB of the primary file.  The data item that joins all the
  62.  * cursors in the curslist is used as the key into the primary and that
  63.  * key and data are returned.  When no more items are left in the join
  64.  * set, the  c_next operation off the join cursor will return DB_NOTFOUND.
  65.  *
  66.  * PUBLIC: int __db_join __P((DB *, DBC **, DBC **, u_int32_t));
  67.  */
  68. int
  69. __db_join(primary, curslist, dbcp, flags)
  70. DB *primary;
  71. DBC **curslist, **dbcp;
  72. u_int32_t flags;
  73. {
  74. DB_ENV *dbenv;
  75. DBC *dbc;
  76. JOIN_CURSOR *jc;
  77. int ret;
  78. u_int32_t i, ncurs, nslots;
  79. COMPQUIET(nslots, 0);
  80. PANIC_CHECK(primary->dbenv);
  81. if ((ret = __db_joinchk(primary, curslist, flags)) != 0)
  82. return (ret);
  83. dbc = NULL;
  84. jc = NULL;
  85. dbenv = primary->dbenv;
  86. if ((ret = __os_calloc(dbenv, 1, sizeof(DBC), &dbc)) != 0)
  87. goto err;
  88. if ((ret = __os_calloc(dbenv,
  89.     1, sizeof(JOIN_CURSOR), &jc)) != 0)
  90. goto err;
  91. if ((ret = __os_malloc(dbenv, 256, NULL, &jc->j_key.data)) != 0)
  92. goto err;
  93. jc->j_key.ulen = 256;
  94. F_SET(&jc->j_key, DB_DBT_USERMEM);
  95. for (jc->j_curslist = curslist;
  96.     *jc->j_curslist != NULL; jc->j_curslist++)
  97. ;
  98. /*
  99.  * The number of cursor slots we allocate is one greater than
  100.  * the number of cursors involved in the join, because the
  101.  * list is NULL-terminated.
  102.  */
  103. ncurs = jc->j_curslist - curslist;
  104. nslots = ncurs + 1;
  105. /*
  106.  * !!! -- A note on the various lists hanging off jc.
  107.  *
  108.  * j_curslist is the initial NULL-terminated list of cursors passed
  109.  * into __db_join.  The original cursors are not modified; pristine
  110.  * copies are required because, in databases with unsorted dups, we
  111.  * must reset all of the secondary cursors after the first each
  112.  * time the first one is incremented, or else we will lose data
  113.  * which happen to be sorted differently in two different cursors.
  114.  *
  115.  * j_workcurs is where we put those copies that we're planning to
  116.  * work with.  They're lazily c_dup'ed from j_curslist as we need
  117.  * them, and closed when the join cursor is closed or when we need
  118.  * to reset them to their original values (in which case we just
  119.  * c_dup afresh).
  120.  *
  121.  * j_fdupcurs is an array of cursors which point to the first
  122.  * duplicate in the duplicate set that contains the data value
  123.  * we're currently interested in.  We need this to make
  124.  * __db_join_get correctly return duplicate duplicates;  i.e., if a
  125.  * given data value occurs twice in the set belonging to cursor #2,
  126.  * and thrice in the set belonging to cursor #3, and once in all
  127.  * the other cursors, successive calls to __db_join_get need to
  128.  * return that data item six times.  To make this happen, each time
  129.  * cursor N is allowed to advance to a new datum, all cursors M
  130.  * such that M > N have to be reset to the first duplicate with
  131.  * that datum, so __db_join_get will return all the dup-dups again.
  132.  * We could just reset them to the original cursor from j_curslist,
  133.  * but that would be a bit slower in the unsorted case and a LOT
  134.  * slower in the sorted one.
  135.  *
  136.  * j_exhausted is a list of boolean values which represent
  137.  * whether or not their corresponding cursors are "exhausted",
  138.  * i.e. whether the datum under the corresponding cursor has
  139.  * been found not to exist in any unreturned combinations of
  140.  * later secondary cursors, in which case they are ready to be
  141.  * incremented.
  142.  */
  143. /* We don't want to free regions whose callocs have failed. */
  144. jc->j_curslist = NULL;
  145. jc->j_workcurs = NULL;
  146. jc->j_fdupcurs = NULL;
  147. jc->j_exhausted = NULL;
  148. if ((ret = __os_calloc(dbenv, nslots, sizeof(DBC *),
  149.     &jc->j_curslist)) != 0)
  150. goto err;
  151. if ((ret = __os_calloc(dbenv, nslots, sizeof(DBC *),
  152.     &jc->j_workcurs)) != 0)
  153. goto err;
  154. if ((ret = __os_calloc(dbenv, nslots, sizeof(DBC *),
  155.     &jc->j_fdupcurs)) != 0)
  156. goto err;
  157. if ((ret = __os_calloc(dbenv, nslots, sizeof(u_int8_t),
  158.     &jc->j_exhausted)) != 0)
  159. goto err;
  160. for (i = 0; curslist[i] != NULL; i++) {
  161. jc->j_curslist[i] = curslist[i];
  162. jc->j_workcurs[i] = NULL;
  163. jc->j_fdupcurs[i] = NULL;
  164. jc->j_exhausted[i] = 0;
  165. }
  166. jc->j_ncurs = ncurs;
  167. /*
  168.  * If DB_JOIN_NOSORT is not set, optimize secondary cursors by
  169.  * sorting in order of increasing cardinality.
  170.  */
  171. if (!LF_ISSET(DB_JOIN_NOSORT))
  172. qsort(jc->j_curslist, ncurs, sizeof(DBC *), __db_join_cmp);
  173. /*
  174.  * We never need to reset the 0th cursor, so there's no
  175.  * solid reason to use workcurs[0] rather than curslist[0] in
  176.  * join_get.  Nonetheless, it feels cleaner to do it for symmetry,
  177.  * and this is the most logical place to copy it.
  178.  *
  179.  * !!!
  180.  * There's no need to close the new cursor if we goto err only
  181.  * because this is the last thing that can fail.  Modifier of this
  182.  * function beware!
  183.  */
  184. if ((ret = jc->j_curslist[0]->c_dup(jc->j_curslist[0], jc->j_workcurs,
  185.     DB_POSITIONI)) != 0)
  186. goto err;
  187. dbc->c_close = __db_join_close;
  188. dbc->c_del = __db_join_del;
  189. dbc->c_get = __db_join_get;
  190. dbc->c_put = __db_join_put;
  191. dbc->internal = (DBC_INTERNAL *) jc;
  192. dbc->dbp = primary;
  193. jc->j_primary = primary;
  194. *dbcp = dbc;
  195. MUTEX_THREAD_LOCK(dbenv, primary->mutexp);
  196. TAILQ_INSERT_TAIL(&primary->join_queue, dbc, links);
  197. MUTEX_THREAD_UNLOCK(dbenv, primary->mutexp);
  198. return (0);
  199. err: if (jc != NULL) {
  200. if (jc->j_curslist != NULL)
  201. __os_free(jc->j_curslist, nslots * sizeof(DBC *));
  202. if (jc->j_workcurs != NULL) {
  203. if (jc->j_workcurs[0] != NULL)
  204. __os_free(jc->j_workcurs[0], sizeof(DBC));
  205. __os_free(jc->j_workcurs, nslots * sizeof(DBC *));
  206. }
  207. if (jc->j_fdupcurs != NULL)
  208. __os_free(jc->j_fdupcurs, nslots * sizeof(DBC *));
  209. if (jc->j_exhausted != NULL)
  210. __os_free(jc->j_exhausted, nslots * sizeof(u_int8_t));
  211. __os_free(jc, sizeof(JOIN_CURSOR));
  212. }
  213. if (dbc != NULL)
  214. __os_free(dbc, sizeof(DBC));
  215. return (ret);
  216. }
  217. static int
  218. __db_join_put(dbc, key, data, flags)
  219. DBC *dbc;
  220. DBT *key;
  221. DBT *data;
  222. u_int32_t flags;
  223. {
  224. PANIC_CHECK(dbc->dbp->dbenv);
  225. COMPQUIET(key, NULL);
  226. COMPQUIET(data, NULL);
  227. COMPQUIET(flags, 0);
  228. return (EINVAL);
  229. }
  230. static int
  231. __db_join_del(dbc, flags)
  232. DBC *dbc;
  233. u_int32_t flags;
  234. {
  235. PANIC_CHECK(dbc->dbp->dbenv);
  236. COMPQUIET(flags, 0);
  237. return (EINVAL);
  238. }
  239. static int
  240. __db_join_get(dbc, key_arg, data_arg, flags)
  241. DBC *dbc;
  242. DBT *key_arg, *data_arg;
  243. u_int32_t flags;
  244. {
  245. DBT *key_n, key_n_mem;
  246. DB *dbp;
  247. DBC *cp;
  248. JOIN_CURSOR *jc;
  249. int ret;
  250. u_int32_t i, j, operation;
  251. dbp = dbc->dbp;
  252. jc = (JOIN_CURSOR *)dbc->internal;
  253. PANIC_CHECK(dbp->dbenv);
  254. operation = LF_ISSET(DB_OPFLAGS_MASK);
  255. if ((ret = __db_joingetchk(dbp, key_arg, flags)) != 0)
  256. return (ret);
  257. /*
  258.  * Since we are fetching the key as a datum in the secondary indices,
  259.  * we must be careful of caller-specified DB_DBT_* memory
  260.  * management flags.  If necessary, use a stack-allocated DBT;
  261.  * we'll appropriately copy and/or allocate the data later.
  262.  */
  263. if (F_ISSET(key_arg, DB_DBT_USERMEM) ||
  264.     F_ISSET(key_arg, DB_DBT_MALLOC)) {
  265. /* We just use the default buffer;  no need to go malloc. */
  266. key_n = &key_n_mem;
  267. memset(key_n, 0, sizeof(DBT));
  268. } else {
  269. /*
  270.  * Either DB_DBT_REALLOC or the default buffer will work
  271.  * fine if we have to reuse it, as we do.
  272.  */
  273. key_n = key_arg;
  274. }
  275. /*
  276.  * If our last attempt to do a get on the primary key failed,
  277.  * short-circuit the join and try again with the same key.
  278.  */
  279. if (F_ISSET(jc, JOIN_RETRY))
  280. goto samekey;
  281. F_CLR(jc, JOIN_RETRY);
  282. retry: ret = jc->j_workcurs[0]->c_get(jc->j_workcurs[0],
  283.     &jc->j_key, key_n, jc->j_exhausted[0] ? DB_NEXT_DUP : DB_CURRENT);
  284. if (ret == ENOMEM) {
  285. jc->j_key.ulen <<= 1;
  286. if ((ret = __os_realloc(dbp->dbenv,
  287.     jc->j_key.ulen, NULL, &jc->j_key.data)) != 0)
  288. goto mem_err;
  289. goto retry;
  290. }
  291. /*
  292.  * If ret == DB_NOTFOUND, we're out of elements of the first
  293.  * secondary cursor.  This is how we finally finish the join
  294.  * if all goes well.
  295.  */
  296. if (ret != 0)
  297. goto err;
  298. /*
  299.  * If jc->j_exhausted[0] == 1, we've just advanced the first cursor,
  300.  * and we're going to want to advance all the cursors that point to
  301.  * the first member of a duplicate duplicate set (j_fdupcurs[1..N]).
  302.  * Close all the cursors in j_fdupcurs;  we'll reopen them the
  303.  * first time through the upcoming loop.
  304.  */
  305. for (i = 1; i < jc->j_ncurs; i++) {
  306. if (jc->j_fdupcurs[i] != NULL &&
  307.     (ret = jc->j_fdupcurs[i]->c_close(jc->j_fdupcurs[i])) != 0)
  308. goto err;
  309. jc->j_fdupcurs[i] = NULL;
  310. }
  311. /*
  312.  * If jc->j_curslist[1] == NULL, we have only one cursor in the join.
  313.  * Thus, we can safely increment that one cursor on each call
  314.  * to __db_join_get, and we signal this by setting jc->j_exhausted[0]
  315.  * right away.
  316.  *
  317.  * Otherwise, reset jc->j_exhausted[0] to 0, so that we don't
  318.  * increment it until we know we're ready to.
  319.  */
  320. if (jc->j_curslist[1] == NULL)
  321. jc->j_exhausted[0] = 1;
  322. else
  323. jc->j_exhausted[0] = 0;
  324. /* We have the first element; now look for it in the other cursors. */
  325. for (i = 1; i < jc->j_ncurs; i++) {
  326. DB_ASSERT(jc->j_curslist[i] != NULL);
  327. if (jc->j_workcurs[i] == NULL)
  328. /* If this is NULL, we need to dup curslist into it. */
  329. if ((ret = jc->j_curslist[i]->c_dup(
  330.     jc->j_curslist[i], jc->j_workcurs + i,
  331.     DB_POSITIONI)) != 0)
  332. goto err;
  333. retry2: cp = jc->j_workcurs[i];
  334. if ((ret = __db_join_getnext(cp, &jc->j_key, key_n,
  335.     jc->j_exhausted[i])) == DB_NOTFOUND) {
  336. /*
  337.  * jc->j_workcurs[i] has no more of the datum we're
  338.  * interested in.  Go back one cursor and get
  339.  * a new dup.  We can't just move to a new
  340.  * element of the outer relation, because that way
  341.  * we might miss duplicate duplicates in cursor i-1.
  342.  *
  343.  * If this takes us back to the first cursor,
  344.  * -then- we can move to a new element of the outer
  345.  * relation.
  346.  */
  347. --i;
  348. jc->j_exhausted[i] = 1;
  349. if (i == 0) {
  350. for (j = 1; jc->j_workcurs[j] != NULL; j++) {
  351. /*
  352.  * We're moving to a new element of
  353.  * the first secondary cursor.  If
  354.  * that cursor is sorted, then any
  355.  * other sorted cursors can be safely
  356.  * reset to the first duplicate
  357.  * duplicate in the current set if we
  358.  * have a pointer to it (we can't just
  359.  * leave them be, or we'll miss
  360.  * duplicate duplicates in the outer
  361.  * relation).
  362.  *
  363.  * If the first cursor is unsorted, or
  364.  * if cursor j is unsorted, we can
  365.  * make no assumptions about what
  366.  * we're looking for next or where it
  367.  * will be, so we reset to the very
  368.  * beginning (setting workcurs NULL
  369.  * will achieve this next go-round).
  370.  *
  371.  * XXX: This is likely to break
  372.  * horribly if any two cursors are
  373.  * both sorted, but have different
  374.  * specified sort functions.  For,
  375.  * now, we dismiss this as pathology
  376.  * and let strange things happen--we
  377.  * can't make rope childproof.
  378.  */
  379. if ((ret = jc->j_workcurs[j]->c_close(
  380.     jc->j_workcurs[j])) != 0)
  381. goto err;
  382. if (!SORTED_SET(jc, 0) ||
  383.     !SORTED_SET(jc, j) ||
  384.     jc->j_fdupcurs[j] == NULL)
  385. /*
  386.  * Unsafe conditions;
  387.  * reset fully.
  388.  */
  389. jc->j_workcurs[j] = NULL;
  390. else
  391. /* Partial reset suffices. */
  392. if ((jc->j_fdupcurs[j]->c_dup(
  393.     jc->j_fdupcurs[j],
  394.     &jc->j_workcurs[j],
  395.     DB_POSITIONI)) != 0)
  396. goto err;
  397. jc->j_exhausted[j] = 0;
  398. }
  399. goto retry;
  400. /* NOTREACHED */
  401. }
  402. /*
  403.  * We're about to advance the cursor and need to
  404.  * reset all of the workcurs[j] where j>i, so that
  405.  * we don't miss any duplicate duplicates.
  406.  */
  407. for (j = i + 1;
  408.     jc->j_workcurs[j] != NULL;
  409.     j++) {
  410. if ((ret = jc->j_workcurs[j]->c_close(
  411.     jc->j_workcurs[j])) != 0)
  412. goto err;
  413. jc->j_exhausted[j] = 0;
  414. if (jc->j_fdupcurs[j] != NULL &&
  415.     (ret = jc->j_fdupcurs[j]->c_dup(
  416.     jc->j_fdupcurs[j], &jc->j_workcurs[j],
  417.     DB_POSITIONI)) != 0)
  418. goto err;
  419. else
  420. jc->j_workcurs[j] = NULL;
  421. }
  422. goto retry2;
  423. /* NOTREACHED */
  424. }
  425. if (ret == ENOMEM) {
  426. jc->j_key.ulen <<= 1;
  427. if ((ret = __os_realloc(dbp->dbenv, jc->j_key.ulen,
  428.     NULL, &jc->j_key.data)) != 0) {
  429. mem_err: __db_err(dbp->dbenv,
  430.     "Allocation failed for join key, len = %lu",
  431.     (u_long)jc->j_key.ulen);
  432. goto err;
  433. }
  434. goto retry2;
  435. }
  436. if (ret != 0)
  437. goto err;
  438. /*
  439.  * If we made it this far, we've found a matching
  440.  * datum in cursor i.  Mark the current cursor
  441.  * unexhausted, so we don't miss any duplicate
  442.  * duplicates the next go-round--unless this is the
  443.  * very last cursor, in which case there are none to
  444.  * miss, and we'll need that exhausted flag to finally
  445.  * get a DB_NOTFOUND and move on to the next datum in
  446.  * the outermost cursor.
  447.  */
  448. if (i + 1 != jc->j_ncurs)
  449. jc->j_exhausted[i] = 0;
  450. else
  451. jc->j_exhausted[i] = 1;
  452. /*
  453.  * If jc->j_fdupcurs[i] is NULL and the ith cursor's dups are
  454.  * sorted, then we're here for the first time since advancing
  455.  * cursor 0, and we have a new datum of interest.
  456.  * jc->j_workcurs[i] points to the beginning of a set of
  457.  * duplicate duplicates;  store this into jc->j_fdupcurs[i].
  458.  */
  459. if (SORTED_SET(jc, i) && jc->j_fdupcurs[i] == NULL && (ret =
  460.     cp->c_dup(cp, &jc->j_fdupcurs[i], DB_POSITIONI)) != 0)
  461. goto err;
  462. }
  463. err: if (ret != 0)
  464. return (ret);
  465. if (0) {
  466. samekey: /*
  467.  * Get the key we tried and failed to return last time;
  468.  * it should be the current datum of all the secondary cursors.
  469.  */
  470. if ((ret = jc->j_workcurs[0]->c_get(jc->j_workcurs[0],
  471.     &jc->j_key, key_n, DB_CURRENT)) != 0)
  472. return (ret);
  473. F_CLR(jc, JOIN_RETRY);
  474. }
  475. /*
  476.  * ret == 0;  we have a key to return.
  477.  *
  478.  * If DB_DBT_USERMEM or DB_DBT_MALLOC is set, we need to
  479.  * copy it back into the dbt we were given for the key;
  480.  * call __db_retcopy.
  481.  *
  482.  * Otherwise, assert that we do not in fact need to copy anything
  483.  * and simply proceed.
  484.  */
  485. if (F_ISSET(key_arg, DB_DBT_USERMEM) ||
  486.     F_ISSET(key_arg, DB_DBT_MALLOC)) {
  487. /*
  488.  * We need to copy the key back into our original
  489.  * datum.  Do so.
  490.  */
  491. if ((ret = __db_retcopy(dbp,
  492.     key_arg, key_n->data, key_n->size, NULL, NULL)) != 0) {
  493. /*
  494.  * The retcopy failed, most commonly because we
  495.  * have a user buffer for the key which is too small.
  496.  * Set things up to retry next time, and return.
  497.  */
  498. F_SET(jc, JOIN_RETRY);
  499. return (ret);
  500. }
  501. } else
  502. DB_ASSERT(key_n == key_arg);
  503. /*
  504.  * If DB_JOIN_ITEM is
  505.  * set, we return it;  otherwise we do the lookup in the
  506.  * primary and then return.
  507.  *
  508.  * Note that we use key_arg here;  it is safe (and appropriate)
  509.  * to do so.
  510.  */
  511. if (operation == DB_JOIN_ITEM)
  512. return (0);
  513. if ((ret = jc->j_primary->get(jc->j_primary,
  514.     jc->j_curslist[0]->txn, key_arg, data_arg, 0)) != 0)
  515. /*
  516.  * The get on the primary failed, most commonly because we're
  517.  * using a user buffer that's not big enough.  Flag our
  518.  * failure so we can return the same key next time.
  519.  */
  520. F_SET(jc, JOIN_RETRY);
  521. return (ret);
  522. }
  523. static int
  524. __db_join_close(dbc)
  525. DBC *dbc;
  526. {
  527. DB *dbp;
  528. JOIN_CURSOR *jc;
  529. int ret, t_ret;
  530. u_int32_t i;
  531. jc = (JOIN_CURSOR *)dbc->internal;
  532. dbp = dbc->dbp;
  533. ret = t_ret = 0;
  534. /*
  535.  * Remove from active list of join cursors.  Note that this
  536.  * must happen before any action that can fail and return, or else
  537.  * __db_close may loop indefinitely.
  538.  */
  539. MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp);
  540. TAILQ_REMOVE(&dbp->join_queue, dbc, links);
  541. MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp);
  542. PANIC_CHECK(dbc->dbp->dbenv);
  543. /*
  544.  * Close any open scratch cursors.  In each case, there may
  545.  * not be as many outstanding as there are cursors in
  546.  * curslist, but we want to close whatever's there.
  547.  *
  548.  * If any close fails, there's no reason not to close everything else;
  549.  * we'll just return the error code of the last one to fail.  There's
  550.  * not much the caller can do anyway, since these cursors only exist
  551.  * hanging off a db-internal data structure that they shouldn't be
  552.  * mucking with.
  553.  */
  554. for (i = 0; i < jc->j_ncurs; i++) {
  555. if (jc->j_workcurs[i] != NULL && (t_ret =
  556.     jc->j_workcurs[i]->c_close(jc->j_workcurs[i])) != 0)
  557. ret = t_ret;
  558. if (jc->j_fdupcurs[i] != NULL && (t_ret =
  559.     jc->j_fdupcurs[i]->c_close(jc->j_fdupcurs[i])) != 0)
  560. ret = t_ret;
  561. }
  562. __os_free(jc->j_exhausted, 0);
  563. __os_free(jc->j_curslist, 0);
  564. __os_free(jc->j_workcurs, 0);
  565. __os_free(jc->j_fdupcurs, 0);
  566. __os_free(jc->j_key.data, jc->j_key.ulen);
  567. __os_free(jc, sizeof(JOIN_CURSOR));
  568. __os_free(dbc, sizeof(DBC));
  569. return (ret);
  570. }
  571. /*
  572.  * __db_join_getnext --
  573.  * This function replaces the DBC_CONTINUE and DBC_KEYSET
  574.  * functionality inside the various cursor get routines.
  575.  *
  576.  * If exhausted == 0, we're not done with the current datum;
  577.  * return it if it matches "matching", otherwise search
  578.  * using DB_GET_BOTHC (which is faster than iteratively doing
  579.  * DB_NEXT_DUP) forward until we find one that does.
  580.  *
  581.  * If exhausted == 1, we are done with the current datum, so just
  582.  * leap forward to searching NEXT_DUPs.
  583.  *
  584.  * If no matching datum exists, returns DB_NOTFOUND, else 0.
  585.  */
  586. static int
  587. __db_join_getnext(dbc, key, data, exhausted)
  588. DBC *dbc;
  589. DBT *key, *data;
  590. u_int32_t exhausted;
  591. {
  592. int ret, cmp;
  593. DB *dbp;
  594. DBT ldata;
  595. int (*func) __P((DB *, const DBT *, const DBT *));
  596. dbp = dbc->dbp;
  597. func = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare;
  598. switch (exhausted) {
  599. case 0:
  600. memset(&ldata, 0, sizeof(DBT));
  601. /* We don't want to step on data->data;  malloc. */
  602. F_SET(&ldata, DB_DBT_MALLOC);
  603. if ((ret = dbc->c_get(dbc, key, &ldata, DB_CURRENT)) != 0)
  604. break;
  605. cmp = func(dbp, data, &ldata);
  606. if (cmp == 0) {
  607. /*
  608.  * We have to return the real data value.  Copy
  609.  * it into data, then free the buffer we malloc'ed
  610.  * above.
  611.  */
  612. if ((ret = __db_retcopy(dbp, data, ldata.data,
  613.     ldata.size, &data->data, &data->size)) != 0)
  614. return (ret);
  615. __os_free(ldata.data, 0);
  616. return (0);
  617. }
  618. /*
  619.  * Didn't match--we want to fall through and search future
  620.  * dups.  We just forget about ldata and free
  621.  * its buffer--data contains the value we're searching for.
  622.  */
  623. __os_free(ldata.data, 0);
  624. /* FALLTHROUGH */
  625. case 1:
  626. ret = dbc->c_get(dbc, key, data, DB_GET_BOTHC);
  627. break;
  628. default:
  629. ret = EINVAL;
  630. break;
  631. }
  632. return (ret);
  633. }
  634. /*
  635.  * __db_join_cmp --
  636.  * Comparison function for sorting DBCs in cardinality order.
  637.  */
  638. static int
  639. __db_join_cmp(a, b)
  640. const void *a, *b;
  641. {
  642. DBC *dbca, *dbcb;
  643. db_recno_t counta, countb;
  644. /* In case c_count fails, pretend cursors are equal. */
  645. counta = countb = 0;
  646. dbca = *((DBC * const *)a);
  647. dbcb = *((DBC * const *)b);
  648. if (dbca->c_count(dbca, &counta, 0) != 0 ||
  649.     dbcb->c_count(dbcb, &countb, 0) != 0)
  650. return (0);
  651. return (counta - countb);
  652. }