/* * __curindex_search_near -- * WT_CURSOR->search_near method for index cursors. */ static int __curindex_search_near(WT_CURSOR *cursor, int *exact) { WT_CURSOR *child; WT_CURSOR_INDEX *cindex; WT_DECL_RET; WT_ITEM found_key; WT_SESSION_IMPL *session; int cmp; cindex = (WT_CURSOR_INDEX *)cursor; child = cindex->child; JOINABLE_CURSOR_API_CALL(cursor, session, search, NULL); /* * We are searching using the application-specified key, which * (usually) doesn't contain the primary key, so it is just a prefix of * any matching index key. That said, if there is an exact match, we * want to find the first matching index entry and set exact equal to * zero. * * Do a search_near, and if we find an entry that is too small, step to * the next one. In the unlikely event of a search past the end of the * tree, go back to the last key. */ __wt_cursor_set_raw_key(child, &cursor->key); WT_ERR(child->search_near(child, &cmp)); if (cmp < 0) { if ((ret = child->next(child)) == WT_NOTFOUND) ret = child->prev(child); WT_ERR(ret); } /* * We expect partial matches, and want the smallest record with a key * greater than or equal to the search key. * * If the found key starts with the search key, we indicate a match by * setting exact equal to zero. * * The compare function expects application-supplied keys to come first * so we flip the sign of the result to match what callers expect. */ found_key = child->key; if (found_key.size > cursor->key.size) found_key.size = cursor->key.size; WT_ERR(__wt_compare( session, cindex->index->collator, &cursor->key, &found_key, exact)); *exact = -*exact; WT_ERR(__curindex_move(cindex)); if (0) { err: F_CLR(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT); } API_END_RET(session, ret); }
/* * __curindex_search -- * WT_CURSOR->search method for index cursors. */ static int __curindex_search(WT_CURSOR *cursor) { WT_CURSOR *child; WT_CURSOR_INDEX *cindex; WT_DECL_RET; WT_ITEM found_key; WT_SESSION_IMPL *session; int cmp; cindex = (WT_CURSOR_INDEX *)cursor; child = cindex->child; JOINABLE_CURSOR_API_CALL(cursor, session, search, NULL); /* * We are searching using the application-specified key, which * (usually) doesn't contain the primary key, so it is just a prefix of * any matching index key. Do a search_near, step to the next entry if * we land on one that is too small, then check that the prefix * matches. */ __wt_cursor_set_raw_key(child, &cursor->key); WT_ERR(child->search_near(child, &cmp)); if (cmp < 0) WT_ERR(child->next(child)); /* * We expect partial matches, and want the smallest record with a key * greater than or equal to the search key. * * If the key we find is shorter than the search key, it can't possibly * match. * * The only way for the key to be exactly equal is if there is an index * on the primary key, because otherwise the primary key columns will * be appended to the index key, but we don't disallow that (odd) case. */ found_key = child->key; if (found_key.size < cursor->key.size) WT_ERR(WT_NOTFOUND); found_key.size = cursor->key.size; WT_ERR(__wt_compare( session, cindex->index->collator, &cursor->key, &found_key, &cmp)); if (cmp != 0) { ret = WT_NOTFOUND; goto err; } WT_ERR(__curindex_move(cindex)); if (0) { err: F_CLR(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT); } API_END_RET(session, ret); }
/* * __curindex_set_value -- * WT_CURSOR->set_value implementation for index cursors. */ static void __curindex_set_value(WT_CURSOR *cursor, ...) { WT_DECL_RET; WT_SESSION_IMPL *session; JOINABLE_CURSOR_API_CALL(cursor, session, set_value, NULL); ret = ENOTSUP; err: cursor->saved_err = ret; F_CLR(cursor, WT_CURSTD_VALUE_SET); API_END(session, ret); }
/* * __wt_curtable_get_value -- * WT_CURSOR->get_value implementation for tables. */ int __wt_curtable_get_value(WT_CURSOR *cursor, ...) { WT_DECL_RET; WT_SESSION_IMPL *session; va_list ap; va_start(ap, cursor); JOINABLE_CURSOR_API_CALL(cursor, session, get_value, NULL); WT_ERR(__wt_curtable_get_valuev(cursor, ap)); err: va_end(ap); API_END_RET(session, ret); }
/* * __curindex_set_value -- * WT_CURSOR->set_value implementation for index cursors. */ static void __curindex_set_value(WT_CURSOR *cursor, ...) { WT_DECL_RET; WT_SESSION_IMPL *session; JOINABLE_CURSOR_API_CALL(cursor, session, set_value, NULL); WT_ERR_MSG(session, ENOTSUP, "WT_CURSOR.set_value not supported for index cursors"); err: cursor->saved_err = ret; F_CLR(cursor, WT_CURSTD_VALUE_SET); API_END(session, ret); }
/* * __curindex_prev -- * WT_CURSOR->prev method for index cursors. */ static int __curindex_prev(WT_CURSOR *cursor) { WT_CURSOR_INDEX *cindex; WT_DECL_RET; WT_SESSION_IMPL *session; cindex = (WT_CURSOR_INDEX *)cursor; JOINABLE_CURSOR_API_CALL(cursor, session, prev, NULL); F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET); if ((ret = cindex->child->prev(cindex->child)) == 0) ret = __curindex_move(cindex); err: API_END_RET(session, ret); }
/* * __curindex_search_near -- * WT_CURSOR->search_near method for index cursors. */ static int __curindex_search_near(WT_CURSOR *cursor, int *exact) { WT_CURSOR_INDEX *cindex; WT_DECL_RET; WT_SESSION_IMPL *session; cindex = (WT_CURSOR_INDEX *)cursor; JOINABLE_CURSOR_API_CALL(cursor, session, search_near, NULL); __wt_cursor_set_raw_key(cindex->child, &cursor->key); if ((ret = cindex->child->search_near(cindex->child, exact)) == 0) ret = __curindex_move(cindex); else F_CLR(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT); err: API_END_RET(session, ret); }
/* * __curindex_close -- * WT_CURSOR->close method for index cursors. */ static int __curindex_close(WT_CURSOR *cursor) { WT_CURSOR_INDEX *cindex; WT_CURSOR **cp; WT_DECL_RET; WT_INDEX *idx; WT_SESSION_IMPL *session; u_int i; cindex = (WT_CURSOR_INDEX *)cursor; idx = cindex->index; JOINABLE_CURSOR_API_CALL(cursor, session, close, NULL); if ((cp = cindex->cg_cursors) != NULL) for (i = 0, cp = cindex->cg_cursors; i < WT_COLGROUPS(cindex->table); i++, cp++) if (*cp != NULL) { WT_TRET((*cp)->close(*cp)); *cp = NULL; } __wt_free(session, cindex->cg_needvalue); __wt_free(session, cindex->cg_cursors); if (cindex->key_plan != idx->key_plan) __wt_free(session, cindex->key_plan); if (cursor->value_format != cindex->table->value_format) __wt_free(session, cursor->value_format); if (cindex->value_plan != idx->value_plan) __wt_free(session, cindex->value_plan); if (cindex->child != NULL) WT_TRET(cindex->child->close(cindex->child)); __wt_schema_release_table(session, cindex->table); /* The URI is owned by the index. */ cursor->internal_uri = NULL; WT_TRET(__wt_cursor_close(cursor)); err: API_END_RET(session, ret); }
/* * __curjoin_get_key -- * WT_CURSOR->get_key for join cursors. */ static int __curjoin_get_key(WT_CURSOR *cursor, ...) { WT_CURSOR_JOIN *cjoin; WT_DECL_RET; WT_SESSION_IMPL *session; va_list ap; cjoin = (WT_CURSOR_JOIN *)cursor; va_start(ap, cursor); JOINABLE_CURSOR_API_CALL(cursor, session, get_key, NULL); if (!F_ISSET(cjoin, WT_CURJOIN_INITIALIZED) || !cjoin->iter->positioned) WT_ERR_MSG(session, EINVAL, "join cursor must be advanced with next()"); WT_ERR(__wt_cursor_get_keyv(cursor, cursor->flags, ap)); err: va_end(ap); API_END_RET(session, ret); }
/* * __wt_curtable_set_value -- * WT_CURSOR->set_value implementation for tables. */ void __wt_curtable_set_value(WT_CURSOR *cursor, ...) { WT_CURSOR **cp; WT_CURSOR_TABLE *ctable; WT_DECL_RET; WT_ITEM *item, *tmp; WT_SESSION_IMPL *session; va_list ap; u_int i; ctable = (WT_CURSOR_TABLE *)cursor; JOINABLE_CURSOR_API_CALL(cursor, session, set_value, NULL); va_start(ap, cursor); if (F_ISSET(cursor, WT_CURSOR_RAW_OK | WT_CURSTD_DUMP_JSON)) { item = va_arg(ap, WT_ITEM *); cursor->value.data = item->data; cursor->value.size = item->size; ret = __wt_schema_project_slice(session, ctable->cg_cursors, ctable->plan, 0, cursor->value_format, &cursor->value); } else {
/* * __curindex_compare -- * WT_CURSOR->compare method for the index cursor type. */ static int __curindex_compare(WT_CURSOR *a, WT_CURSOR *b, int *cmpp) { WT_CURSOR_INDEX *cindex; WT_DECL_RET; WT_SESSION_IMPL *session; cindex = (WT_CURSOR_INDEX *)a; JOINABLE_CURSOR_API_CALL(a, session, compare, NULL); /* Check both cursors are "index:" type. */ if (!WT_PREFIX_MATCH(a->uri, "index:") || strcmp(a->uri, b->uri) != 0) WT_ERR_MSG(session, EINVAL, "Cursors must reference the same object"); WT_CURSOR_CHECKKEY(a); WT_CURSOR_CHECKKEY(b); ret = __wt_compare( session, cindex->index->collator, &a->key, &b->key, cmpp); err: API_END_RET(session, ret); }
/* * __curindex_reset -- * WT_CURSOR->reset method for index cursors. */ static int __curindex_reset(WT_CURSOR *cursor) { WT_CURSOR **cp; WT_CURSOR_INDEX *cindex; WT_DECL_RET; WT_SESSION_IMPL *session; u_int i; cindex = (WT_CURSOR_INDEX *)cursor; JOINABLE_CURSOR_API_CALL(cursor, session, reset, NULL); F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET); WT_TRET(cindex->child->reset(cindex->child)); for (i = 0, cp = cindex->cg_cursors; i < WT_COLGROUPS(cindex->table); i++, cp++) { if (*cp == NULL) continue; WT_TRET((*cp)->reset(*cp)); } err: API_END_RET(session, ret); }
/* * __curjoin_next -- * WT_CURSOR::next for join cursors. */ static int __curjoin_next(WT_CURSOR *cursor) { WT_CURSOR *c; WT_CURSOR_JOIN *cjoin; WT_CURSOR_JOIN_ITER *iter; WT_DECL_RET; WT_SESSION_IMPL *session; int tret; cjoin = (WT_CURSOR_JOIN *)cursor; JOINABLE_CURSOR_API_CALL(cursor, session, next, NULL); if (F_ISSET(cjoin, WT_CURJOIN_ERROR)) WT_ERR_MSG(session, WT_ERROR, "join cursor encountered previous error"); if (!F_ISSET(cjoin, WT_CURJOIN_INITIALIZED)) WT_ERR(__curjoin_init_next(session, cjoin, true)); if (cjoin->iter == NULL) WT_ERR(__curjoin_iter_init(session, cjoin, &cjoin->iter)); iter = cjoin->iter; F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET); while ((ret = __curjoin_iter_next(iter, cursor)) == 0) { if ((ret = __curjoin_entries_in_range(session, cjoin, iter->curkey, iter)) != WT_NOTFOUND) break; } iter->positioned = (ret == 0); if (ret != 0 && ret != WT_NOTFOUND) WT_ERR(ret); if (ret == 0) { /* * Position the 'main' cursor, this will be used to retrieve * values from the cursor join. The key we have is raw, but * the main cursor may not be raw. */ c = cjoin->main; __wt_cursor_set_raw_key(c, iter->curkey); /* * A failed search is not expected, convert WT_NOTFOUND into a * generic error. */ iter->entry->stats.main_access++; if ((ret = c->search(c)) != 0) { if (ret == WT_NOTFOUND) ret = WT_ERROR; WT_ERR_MSG(session, ret, "join cursor failed search"); } F_SET(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT); } else if (ret == WT_NOTFOUND && (tret = __curjoin_iter_close_all(iter)) != 0) WT_ERR(tret); if (0) { err: F_SET(cjoin, WT_CURJOIN_ERROR); } API_END_RET(session, ret); }