/* * __curjoin_extract_insert -- * Handle a key produced by a custom extractor. */ static int __curjoin_extract_insert(WT_CURSOR *cursor) { WT_CURJOIN_EXTRACTOR *cextract; WT_DECL_RET; WT_ITEM ikey; WT_SESSION_IMPL *session; /* * This insert method may be called multiple times during a single * extraction. If we already have a definitive answer to the * membership question, exit early. */ cextract = (WT_CURJOIN_EXTRACTOR *)cursor; if (cextract->ismember) return (0); CURSOR_API_CALL(cursor, session, insert, NULL); WT_ITEM_SET(ikey, cursor->key); /* * We appended a padding byte to the key to avoid rewriting the last * column. Strip that away here. */ WT_ASSERT(session, ikey.size > 0); --ikey.size; ret = __curjoin_entry_in_range(session, cextract->entry, &ikey, false); if (ret == WT_NOTFOUND) ret = 0; else if (ret == 0) cextract->ismember = true; err: API_END_RET(session, ret); }
/* * __curjoin_split_key -- * Copy the primary key from a cursor (either main table or index) * to another cursor. When copying from an index file, the index * key is also returned. * */ static int __curjoin_split_key(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin, WT_ITEM *idxkey, WT_CURSOR *tocur, WT_CURSOR *fromcur, const char *repack_fmt, bool isindex) { WT_CURSOR *firstcg_cur; WT_CURSOR_INDEX *cindex; WT_ITEM *keyp; const uint8_t *p; if (isindex) { cindex = ((WT_CURSOR_INDEX *)fromcur); /* * Repack tells us where the index key ends; advance past * that to get where the raw primary key starts. */ WT_RET(__wt_struct_repack(session, cindex->child->key_format, repack_fmt != NULL ? repack_fmt : cindex->iface.key_format, &cindex->child->key, idxkey)); WT_ASSERT(session, cindex->child->key.size > idxkey->size); tocur->key.data = (uint8_t *)idxkey->data + idxkey->size; tocur->key.size = cindex->child->key.size - idxkey->size; if (WT_CURSOR_RECNO(tocur)) { p = (const uint8_t *)tocur->key.data; WT_RET(__wt_vunpack_uint(&p, tocur->key.size, &tocur->recno)); } else tocur->recno = 0; } else { firstcg_cur = ((WT_CURSOR_TABLE *)fromcur)->cg_cursors[0]; keyp = &firstcg_cur->key; if (WT_CURSOR_RECNO(tocur)) { WT_ASSERT(session, keyp->size == sizeof(uint64_t)); tocur->recno = *(uint64_t *)keyp->data; WT_RET(__curjoin_pack_recno(session, tocur->recno, cjoin->recno_buf, sizeof(cjoin->recno_buf), &tocur->key)); } else { WT_ITEM_SET(tocur->key, *keyp); tocur->recno = 0; } idxkey->data = NULL; idxkey->size = 0; } return (0); }
/* * __curjoin_entry_iter_next -- * Get the next item in an iteration. * */ static int __curjoin_entry_iter_next(WT_CURSOR_JOIN_ITER *iter, WT_ITEM *primkey, uint64_t *rp) { WT_CURSOR *firstcg_cur; WT_CURSOR_JOIN *cjoin; WT_DECL_RET; WT_SESSION_IMPL *session; uint64_t r; if (iter->advance) WT_ERR(iter->cursor->next(iter->cursor)); else iter->advance = true; session = iter->session; cjoin = iter->cjoin; /* * Set our key to the primary key, we'll also need this * to check membership. */ if (iter->entry->index != NULL) firstcg_cur = ((WT_CURSOR_INDEX *)iter->cursor)->cg_cursors[0]; else firstcg_cur = ((WT_CURSOR_TABLE *)iter->cursor)->cg_cursors[0]; if (WT_CURSOR_RECNO(&cjoin->iface)) { r = *(uint64_t *)firstcg_cur->key.data; WT_ERR(__curjoin_pack_recno(session, r, cjoin->recno_buf, sizeof(cjoin->recno_buf), primkey)); *rp = r; } else { WT_ITEM_SET(*primkey, firstcg_cur->key); *rp = 0; } iter->curkey = primkey; iter->entry->stats.actual_count++; iter->entry->stats.accesses++; err: return (ret); }
/* * __curextract_insert -- * Handle a key produced by a custom extractor. */ static int __curextract_insert(WT_CURSOR *cursor) { WT_CURSOR_EXTRACTOR *cextract; WT_ITEM *key, ikey, pkey; WT_SESSION_IMPL *session; cextract = (WT_CURSOR_EXTRACTOR *)cursor; session = (WT_SESSION_IMPL *)cursor->session; WT_ITEM_SET(ikey, cursor->key); /* * We appended a padding byte to the key to avoid rewriting the last * column. Strip that away here. */ WT_ASSERT(session, ikey.size > 0); --ikey.size; WT_RET(__wt_cursor_get_raw_key(cextract->ctable->cg_cursors[0], &pkey)); /* * We have the index key in the format we need, and all of the primary * key columns are required: just append them. */ key = &cextract->idxc->key; WT_RET(__wt_buf_grow(session, key, ikey.size + pkey.size)); memcpy((uint8_t *)key->mem, ikey.data, ikey.size); memcpy((uint8_t *)key->mem + ikey.size, pkey.data, pkey.size); key->size = ikey.size + pkey.size; /* * The index key is now set and the value is empty (it starts clear and * is never set). */ F_SET(cextract->idxc, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT); /* Call the underlying cursor function to update the index. */ return (cextract->f(cextract->idxc)); }
/* * __curjoin_entry_member -- * Do a membership check for a particular index that was joined, * if not a member, returns WT_NOTFOUND. */ static int __curjoin_entry_member(WT_SESSION_IMPL *session, WT_CURSOR_JOIN_ENTRY *entry, WT_ITEM *key, WT_CURSOR_JOIN_ITER *iter) { WT_CURJOIN_EXTRACTOR extract_cursor; WT_CURSOR *c; WT_CURSOR_STATIC_INIT(iface, __wt_cursor_get_key, /* get-key */ __wt_cursor_get_value, /* get-value */ __wt_cursor_set_key, /* set-key */ __wt_cursor_set_value, /* set-value */ __wt_cursor_compare_notsup, /* compare */ __wt_cursor_equals_notsup, /* equals */ __wt_cursor_notsup, /* next */ __wt_cursor_notsup, /* prev */ __wt_cursor_notsup, /* reset */ __wt_cursor_notsup, /* search */ __wt_cursor_search_near_notsup, /* search-near */ __curjoin_extract_insert, /* insert */ __wt_cursor_modify_notsup, /* modify */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __wt_cursor_notsup); /* close */ WT_DECL_RET; WT_INDEX *idx; WT_ITEM v; bool bloom_found; if (entry->subjoin == NULL && iter != NULL && (iter->end_pos + iter->end_skip >= entry->ends_next || (iter->end_skip > 0 && F_ISSET(entry, WT_CURJOIN_ENTRY_DISJUNCTION)))) return (0); /* no checks to make */ entry->stats.membership_check++; bloom_found = false; if (entry->bloom != NULL) { /* * If the item is not in the Bloom filter, we return * immediately, otherwise, we still may need to check the * long way, since it may be a false positive. * * If we don't own the Bloom filter, we must be sharing one * in a previous entry. So the shared filter has already * been checked and passed, we don't need to check it again. * We'll still need to check the long way. */ if (F_ISSET(entry, WT_CURJOIN_ENTRY_OWN_BLOOM)) WT_ERR(__wt_bloom_inmem_get(entry->bloom, key)); if (F_ISSET(entry, WT_CURJOIN_ENTRY_FALSE_POSITIVES)) return (0); bloom_found = true; } if (entry->subjoin != NULL) { WT_ASSERT(session, iter == NULL || entry->subjoin == iter->child->cjoin); ret = __curjoin_entries_in_range(session, entry->subjoin, key, iter == NULL ? NULL : iter->child); if (iter != NULL && WT_CURJOIN_ITER_CONSUMED(iter->child)) { WT_ERR(__curjoin_iter_bump(iter)); ret = WT_NOTFOUND; } return (ret); } if (entry->index != NULL) { /* * If this entry is used by the iterator, then we already * have the index key, and we won't have to do any * extraction either. */ if (iter != NULL && entry == iter->entry) WT_ITEM_SET(v, iter->idxkey); else { memset(&v, 0, sizeof(v)); /* Keep lint quiet. */ c = entry->main; c->set_key(c, key); entry->stats.main_access++; if ((ret = c->search(c)) == 0) ret = c->get_value(c, &v); else if (ret == WT_NOTFOUND) { __wt_err(session, ret, "main table for join is missing entry"); ret = WT_ERROR; } WT_TRET(c->reset(c)); WT_ERR(ret); } } else WT_ITEM_SET(v, *key); if ((idx = entry->index) != NULL && idx->extractor != NULL && (iter == NULL || entry != iter->entry)) { WT_CLEAR(extract_cursor); extract_cursor.iface = iface; extract_cursor.iface.session = &session->iface; extract_cursor.iface.key_format = idx->exkey_format; extract_cursor.ismember = false; extract_cursor.entry = entry; WT_ERR(idx->extractor->extract(idx->extractor, &session->iface, key, &v, &extract_cursor.iface)); __wt_buf_free(session, &extract_cursor.iface.key); __wt_buf_free(session, &extract_cursor.iface.value); if (!extract_cursor.ismember) WT_ERR(WT_NOTFOUND); } else WT_ERR(__curjoin_entry_in_range(session, entry, &v, iter)); if (0) { err: if (ret == WT_NOTFOUND && bloom_found) entry->stats.bloom_false_positive++; } return (ret); }