diff options
Diffstat (limited to 'src/third_party/wiredtiger/src/cursor/cur_table.c')
-rw-r--r-- | src/third_party/wiredtiger/src/cursor/cur_table.c | 1716 |
1 files changed, 840 insertions, 876 deletions
diff --git a/src/third_party/wiredtiger/src/cursor/cur_table.c b/src/third_party/wiredtiger/src/cursor/cur_table.c index 3198a15bd13..fdf10a558a4 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_table.c +++ b/src/third_party/wiredtiger/src/cursor/cur_table.c @@ -11,1095 +11,1059 @@ static int __curtable_open_indices(WT_CURSOR_TABLE *ctable); static int __curtable_update(WT_CURSOR *cursor); -#define APPLY_CG(ctable, f) do { \ - WT_CURSOR **__cp; \ - u_int __i; \ - for (__i = 0, __cp = (ctable)->cg_cursors; \ - __i < WT_COLGROUPS((ctable)->table); \ - __i++, __cp++) \ - WT_TRET((*__cp)->f(*__cp)); \ -} while (0) +#define APPLY_CG(ctable, f) \ + do { \ + WT_CURSOR **__cp; \ + u_int __i; \ + for (__i = 0, __cp = (ctable)->cg_cursors; __i < WT_COLGROUPS((ctable)->table); \ + __i++, __cp++) \ + WT_TRET((*__cp)->f(*__cp)); \ + } while (0) /* Cursor type for custom extractor callback. */ typedef struct { - WT_CURSOR iface; - WT_CURSOR_TABLE *ctable; - WT_CURSOR *idxc; - int (*f)(WT_CURSOR *); + WT_CURSOR iface; + WT_CURSOR_TABLE *ctable; + WT_CURSOR *idxc; + int (*f)(WT_CURSOR *); } WT_CURSOR_EXTRACTOR; /* * __curextract_insert -- - * Handle a key produced by a custom extractor. + * Handle a key produced by a custom extractor. */ static int __curextract_insert(WT_CURSOR *cursor) { - WT_CURSOR_EXTRACTOR *cextract; - WT_DECL_RET; - WT_ITEM *key, ikey, pkey; - WT_SESSION_IMPL *session; - - CURSOR_API_CALL(cursor, session, insert, NULL); - - cextract = (WT_CURSOR_EXTRACTOR *)cursor; - - 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_ERR(__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_ERR(__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. */ - ret = cextract->f(cextract->idxc); - -err: API_END_RET(session, ret); + WT_CURSOR_EXTRACTOR *cextract; + WT_DECL_RET; + WT_ITEM *key, ikey, pkey; + WT_SESSION_IMPL *session; + + CURSOR_API_CALL(cursor, session, insert, NULL); + + cextract = (WT_CURSOR_EXTRACTOR *)cursor; + + 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_ERR(__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_ERR(__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. */ + ret = cextract->f(cextract->idxc); + +err: + API_END_RET(session, ret); } /* * __wt_apply_single_idx -- - * Apply an operation to a single index of a table. + * Apply an operation to a single index of a table. */ int -__wt_apply_single_idx(WT_SESSION_IMPL *session, WT_INDEX *idx, - WT_CURSOR *cur, WT_CURSOR_TABLE *ctable, int (*f)(WT_CURSOR *)) +__wt_apply_single_idx(WT_SESSION_IMPL *session, WT_INDEX *idx, WT_CURSOR *cur, + WT_CURSOR_TABLE *ctable, int (*f)(WT_CURSOR *)) { - 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 */ - __curextract_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_CURSOR_EXTRACTOR extract_cursor; - WT_DECL_RET; - WT_ITEM key, value; - - if (idx->extractor) { - extract_cursor.iface = iface; - extract_cursor.iface.session = &session->iface; - extract_cursor.iface.key_format = idx->exkey_format; - extract_cursor.ctable = ctable; - extract_cursor.idxc = cur; - extract_cursor.f = f; - - WT_RET(__wt_cursor_get_raw_key(&ctable->iface, &key)); - WT_RET(__wt_cursor_get_raw_value(&ctable->iface, &value)); - ret = idx->extractor->extract(idx->extractor, - &session->iface, &key, &value, &extract_cursor.iface); - - __wt_buf_free(session, &extract_cursor.iface.key); - WT_RET(ret); - } else { - WT_RET(__wt_schema_project_merge(session, - ctable->cg_cursors, - idx->key_plan, idx->key_format, &cur->key)); - /* - * The index key is now set and the value is empty - * (it starts clear and is never set). - */ - F_SET(cur, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT); - WT_RET(f(cur)); - } - return (0); + 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 */ + __curextract_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_CURSOR_EXTRACTOR extract_cursor; + WT_DECL_RET; + WT_ITEM key, value; + + if (idx->extractor) { + extract_cursor.iface = iface; + extract_cursor.iface.session = &session->iface; + extract_cursor.iface.key_format = idx->exkey_format; + extract_cursor.ctable = ctable; + extract_cursor.idxc = cur; + extract_cursor.f = f; + + WT_RET(__wt_cursor_get_raw_key(&ctable->iface, &key)); + WT_RET(__wt_cursor_get_raw_value(&ctable->iface, &value)); + ret = idx->extractor->extract( + idx->extractor, &session->iface, &key, &value, &extract_cursor.iface); + + __wt_buf_free(session, &extract_cursor.iface.key); + WT_RET(ret); + } else { + WT_RET(__wt_schema_project_merge( + session, ctable->cg_cursors, idx->key_plan, idx->key_format, &cur->key)); + /* + * The index key is now set and the value is empty + * (it starts clear and is never set). + */ + F_SET(cur, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT); + WT_RET(f(cur)); + } + return (0); } /* * __apply_idx -- - * Apply an operation to all indices of a table. + * Apply an operation to all indices of a table. */ static int __apply_idx(WT_CURSOR_TABLE *ctable, size_t func_off, bool skip_immutable) { - WT_CURSOR **cp; - WT_INDEX *idx; - WT_SESSION_IMPL *session; - u_int i; - int (*f)(WT_CURSOR *); - - cp = ctable->idx_cursors; - session = (WT_SESSION_IMPL *)ctable->iface.session; - - for (i = 0; i < ctable->table->nindices; i++, cp++) { - idx = ctable->table->indices[i]; - if (skip_immutable && F_ISSET(idx, WT_INDEX_IMMUTABLE)) - continue; - - f = *(int (**)(WT_CURSOR *))((uint8_t *)*cp + func_off); - WT_RET(__wt_apply_single_idx(session, idx, *cp, ctable, f)); - WT_RET((*cp)->reset(*cp)); - } - - return (0); + WT_CURSOR **cp; + WT_INDEX *idx; + WT_SESSION_IMPL *session; + u_int i; + int (*f)(WT_CURSOR *); + + cp = ctable->idx_cursors; + session = (WT_SESSION_IMPL *)ctable->iface.session; + + for (i = 0; i < ctable->table->nindices; i++, cp++) { + idx = ctable->table->indices[i]; + if (skip_immutable && F_ISSET(idx, WT_INDEX_IMMUTABLE)) + continue; + + f = *(int (**)(WT_CURSOR *))((uint8_t *)*cp + func_off); + WT_RET(__wt_apply_single_idx(session, idx, *cp, ctable, f)); + WT_RET((*cp)->reset(*cp)); + } + + return (0); } /* * __wt_curtable_get_key -- - * WT_CURSOR->get_key implementation for tables. + * WT_CURSOR->get_key implementation for tables. */ int __wt_curtable_get_key(WT_CURSOR *cursor, ...) { - WT_CURSOR *primary; - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - va_list ap; + WT_CURSOR *primary; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + va_list ap; - ctable = (WT_CURSOR_TABLE *)cursor; - primary = *ctable->cg_cursors; + ctable = (WT_CURSOR_TABLE *)cursor; + primary = *ctable->cg_cursors; - va_start(ap, cursor); - ret = __wt_cursor_get_keyv(primary, cursor->flags, ap); - va_end(ap); + va_start(ap, cursor); + ret = __wt_cursor_get_keyv(primary, cursor->flags, ap); + va_end(ap); - return (ret); + return (ret); } /* * __wt_curtable_get_value -- - * WT_CURSOR->get_value implementation for tables. + * 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; + WT_DECL_RET; + WT_SESSION_IMPL *session; + va_list ap; - JOINABLE_CURSOR_API_CALL(cursor, session, get_value, NULL); + JOINABLE_CURSOR_API_CALL(cursor, session, get_value, NULL); - va_start(ap, cursor); - ret = __wt_curtable_get_valuev(cursor, ap); - va_end(ap); + va_start(ap, cursor); + ret = __wt_curtable_get_valuev(cursor, ap); + va_end(ap); -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __wt_curtable_set_key -- - * WT_CURSOR->set_key implementation for tables. + * WT_CURSOR->set_key implementation for tables. */ void __wt_curtable_set_key(WT_CURSOR *cursor, ...) { - WT_CURSOR **cp, *primary; - WT_CURSOR_TABLE *ctable; - u_int i; - va_list ap; - - ctable = (WT_CURSOR_TABLE *)cursor; - cp = ctable->cg_cursors; - primary = *cp++; - - va_start(ap, cursor); - __wt_cursor_set_keyv(primary, cursor->flags, ap); - va_end(ap); - - if (!F_ISSET(primary, WT_CURSTD_KEY_SET)) - return; - - /* Copy the primary key to the other cursors. */ - for (i = 1; i < WT_COLGROUPS(ctable->table); i++, cp++) { - (*cp)->recno = primary->recno; - (*cp)->key.data = primary->key.data; - (*cp)->key.size = primary->key.size; - F_SET(*cp, WT_CURSTD_KEY_EXT); - } + WT_CURSOR **cp, *primary; + WT_CURSOR_TABLE *ctable; + u_int i; + va_list ap; + + ctable = (WT_CURSOR_TABLE *)cursor; + cp = ctable->cg_cursors; + primary = *cp++; + + va_start(ap, cursor); + __wt_cursor_set_keyv(primary, cursor->flags, ap); + va_end(ap); + + if (!F_ISSET(primary, WT_CURSTD_KEY_SET)) + return; + + /* Copy the primary key to the other cursors. */ + for (i = 1; i < WT_COLGROUPS(ctable->table); i++, cp++) { + (*cp)->recno = primary->recno; + (*cp)->key.data = primary->key.data; + (*cp)->key.size = primary->key.size; + F_SET(*cp, WT_CURSTD_KEY_EXT); + } } /* * __wt_curtable_set_value -- - * WT_CURSOR->set_value implementation for tables. + * 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; - u_int i; - va_list ap; - - 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 { - /* - * The user may be passing us pointers returned by get_value - * that point into the buffers we are about to update. - * Move them aside first. - */ - for (i = 0, cp = ctable->cg_cursors; - i < WT_COLGROUPS(ctable->table); i++, cp++) { - item = &(*cp)->value; - if (F_ISSET(*cp, WT_CURSTD_VALUE_SET) && - WT_DATA_IN_ITEM(item)) { - ctable->cg_valcopy[i] = *item; - item->mem = NULL; - item->memsize = 0; - } - } - - ret = __wt_schema_project_in(session, - ctable->cg_cursors, ctable->plan, ap); - - for (i = 0, cp = ctable->cg_cursors; - i < WT_COLGROUPS(ctable->table); i++, cp++) { - tmp = &ctable->cg_valcopy[i]; - if (tmp->mem != NULL) { - item = &(*cp)->value; - if (item->mem == NULL) { - item->mem = tmp->mem; - item->memsize = tmp->memsize; - } else - __wt_free(session, tmp->mem); - } - } - - } - va_end(ap); - - for (i = 0, cp = ctable->cg_cursors; - i < WT_COLGROUPS(ctable->table); i++, cp++) - if (ret == 0) - F_SET(*cp, WT_CURSTD_VALUE_EXT); - else { - (*cp)->saved_err = ret; - F_CLR(*cp, WT_CURSTD_VALUE_SET); - } - -err: API_END(session, ret); + WT_CURSOR **cp; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_ITEM *item, *tmp; + WT_SESSION_IMPL *session; + u_int i; + va_list ap; + + 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 { + /* + * The user may be passing us pointers returned by get_value that point into the buffers we + * are about to update. Move them aside first. + */ + for (i = 0, cp = ctable->cg_cursors; i < WT_COLGROUPS(ctable->table); i++, cp++) { + item = &(*cp)->value; + if (F_ISSET(*cp, WT_CURSTD_VALUE_SET) && WT_DATA_IN_ITEM(item)) { + ctable->cg_valcopy[i] = *item; + item->mem = NULL; + item->memsize = 0; + } + } + + ret = __wt_schema_project_in(session, ctable->cg_cursors, ctable->plan, ap); + + for (i = 0, cp = ctable->cg_cursors; i < WT_COLGROUPS(ctable->table); i++, cp++) { + tmp = &ctable->cg_valcopy[i]; + if (tmp->mem != NULL) { + item = &(*cp)->value; + if (item->mem == NULL) { + item->mem = tmp->mem; + item->memsize = tmp->memsize; + } else + __wt_free(session, tmp->mem); + } + } + } + va_end(ap); + + for (i = 0, cp = ctable->cg_cursors; i < WT_COLGROUPS(ctable->table); i++, cp++) + if (ret == 0) + F_SET(*cp, WT_CURSTD_VALUE_EXT); + else { + (*cp)->saved_err = ret; + F_CLR(*cp, WT_CURSTD_VALUE_SET); + } + +err: + API_END(session, ret); } /* * __curtable_compare -- - * WT_CURSOR->compare implementation for tables. + * WT_CURSOR->compare implementation for tables. */ static int __curtable_compare(WT_CURSOR *a, WT_CURSOR *b, int *cmpp) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - JOINABLE_CURSOR_API_CALL(a, session, compare, NULL); + JOINABLE_CURSOR_API_CALL(a, session, compare, NULL); - /* - * Confirm both cursors refer to the same source and have keys, then - * call the underlying object's comparison routine. - */ - if (strcmp(a->internal_uri, b->internal_uri) != 0) - WT_ERR_MSG(session, EINVAL, - "comparison method cursors must reference the same object"); - WT_ERR(__cursor_checkkey(WT_CURSOR_PRIMARY(a))); - WT_ERR(__cursor_checkkey(WT_CURSOR_PRIMARY(b))); + /* + * Confirm both cursors refer to the same source and have keys, then call the underlying + * object's comparison routine. + */ + if (strcmp(a->internal_uri, b->internal_uri) != 0) + WT_ERR_MSG(session, EINVAL, "comparison method cursors must reference the same object"); + WT_ERR(__cursor_checkkey(WT_CURSOR_PRIMARY(a))); + WT_ERR(__cursor_checkkey(WT_CURSOR_PRIMARY(b))); - ret = WT_CURSOR_PRIMARY(a)->compare( - WT_CURSOR_PRIMARY(a), WT_CURSOR_PRIMARY(b), cmpp); + ret = WT_CURSOR_PRIMARY(a)->compare(WT_CURSOR_PRIMARY(a), WT_CURSOR_PRIMARY(b), cmpp); -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __curtable_next -- - * WT_CURSOR->next method for the table cursor type. + * WT_CURSOR->next method for the table cursor type. */ static int __curtable_next(WT_CURSOR *cursor) { - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_API_CALL(cursor, session, next, NULL); - APPLY_CG(ctable, next); + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_API_CALL(cursor, session, next, NULL); + APPLY_CG(ctable, next); -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __curtable_next_random -- - * WT_CURSOR->next method for the table cursor type when configured with - * next_random. + * WT_CURSOR->next method for the table cursor type when configured with next_random. */ static int __curtable_next_random(WT_CURSOR *cursor) { - WT_CURSOR *primary, **cp; - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; - u_int i; - - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_API_CALL(cursor, session, next, NULL); - cp = ctable->cg_cursors; - - /* Split out the first next, it retrieves the random record. */ - primary = *cp++; - WT_ERR(primary->next(primary)); - - /* Fill in the rest of the columns. */ - for (i = 1; i < WT_COLGROUPS(ctable->table); i++, cp++) { - (*cp)->key.data = primary->key.data; - (*cp)->key.size = primary->key.size; - (*cp)->recno = primary->recno; - F_SET(*cp, WT_CURSTD_KEY_EXT); - WT_ERR((*cp)->search(*cp)); - } - -err: API_END_RET(session, ret); + WT_CURSOR *primary, **cp; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; + u_int i; + + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_API_CALL(cursor, session, next, NULL); + cp = ctable->cg_cursors; + + /* Split out the first next, it retrieves the random record. */ + primary = *cp++; + WT_ERR(primary->next(primary)); + + /* Fill in the rest of the columns. */ + for (i = 1; i < WT_COLGROUPS(ctable->table); i++, cp++) { + (*cp)->key.data = primary->key.data; + (*cp)->key.size = primary->key.size; + (*cp)->recno = primary->recno; + F_SET(*cp, WT_CURSTD_KEY_EXT); + WT_ERR((*cp)->search(*cp)); + } + +err: + API_END_RET(session, ret); } /* * __curtable_prev -- - * WT_CURSOR->prev method for the table cursor type. + * WT_CURSOR->prev method for the table cursor type. */ static int __curtable_prev(WT_CURSOR *cursor) { - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_API_CALL(cursor, session, prev, NULL); - APPLY_CG(ctable, prev); + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_API_CALL(cursor, session, prev, NULL); + APPLY_CG(ctable, prev); -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __curtable_reset -- - * WT_CURSOR->reset method for the table cursor type. + * WT_CURSOR->reset method for the table cursor type. */ static int __curtable_reset(WT_CURSOR *cursor) { - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_API_CALL_PREPARE_ALLOWED(cursor, session, reset, NULL); - APPLY_CG(ctable, reset); + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_API_CALL_PREPARE_ALLOWED(cursor, session, reset, NULL); + APPLY_CG(ctable, reset); -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __curtable_search -- - * WT_CURSOR->search method for the table cursor type. + * WT_CURSOR->search method for the table cursor type. */ static int __curtable_search(WT_CURSOR *cursor) { - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_API_CALL(cursor, session, search, NULL); - APPLY_CG(ctable, search); + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_API_CALL(cursor, session, search, NULL); + APPLY_CG(ctable, search); -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __curtable_search_near -- - * WT_CURSOR->search_near method for the table cursor type. + * WT_CURSOR->search_near method for the table cursor type. */ static int __curtable_search_near(WT_CURSOR *cursor, int *exact) { - WT_CURSOR *primary, **cp; - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; - u_int i; - - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_API_CALL(cursor, session, search_near, NULL); - cp = ctable->cg_cursors; - primary = *cp; - WT_ERR(primary->search_near(primary, exact)); - - for (i = 1, ++cp; i < WT_COLGROUPS(ctable->table); i++) { - (*cp)->key.data = primary->key.data; - (*cp)->key.size = primary->key.size; - (*cp)->recno = primary->recno; - F_SET(*cp, WT_CURSTD_KEY_EXT); - WT_ERR((*cp)->search(*cp)); - } - -err: API_END_RET(session, ret); + WT_CURSOR *primary, **cp; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; + u_int i; + + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_API_CALL(cursor, session, search_near, NULL); + cp = ctable->cg_cursors; + primary = *cp; + WT_ERR(primary->search_near(primary, exact)); + + for (i = 1, ++cp; i < WT_COLGROUPS(ctable->table); i++) { + (*cp)->key.data = primary->key.data; + (*cp)->key.size = primary->key.size; + (*cp)->recno = primary->recno; + F_SET(*cp, WT_CURSTD_KEY_EXT); + WT_ERR((*cp)->search(*cp)); + } + +err: + API_END_RET(session, ret); } /* * __curtable_insert -- - * WT_CURSOR->insert method for the table cursor type. + * WT_CURSOR->insert method for the table cursor type. */ static int __curtable_insert(WT_CURSOR *cursor) { - WT_CURSOR *primary, **cp; - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; - uint32_t flag_orig; - u_int i; - - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_UPDATE_API_CALL(cursor, session, insert); - WT_ERR(__curtable_open_indices(ctable)); - - /* - * Split out the first insert, it may be allocating a recno. - * - * If the table has indices, we also need to know whether this record - * is replacing an existing record so that the existing index entries - * can be removed. We discover if this is an overwrite by configuring - * the primary cursor for no-overwrite, and checking if the insert - * detects a duplicate key. - */ - cp = ctable->cg_cursors; - primary = *cp++; - - flag_orig = F_MASK(primary, WT_CURSTD_OVERWRITE); - if (ctable->table->nindices > 0) - F_CLR(primary, WT_CURSTD_OVERWRITE); - ret = primary->insert(primary); - - /* - * !!! - * WT_CURSOR.insert clears the set internally/externally flags - * but doesn't touch the items. We could make a copy each time - * for overwrite cursors, but for now we just reset the flags. - */ - F_SET(primary, flag_orig | WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT); - - if (ret == WT_DUPLICATE_KEY && F_ISSET(cursor, WT_CURSTD_OVERWRITE)) { - WT_ERR(__curtable_update(cursor)); - - /* - * The cursor is no longer positioned. This isn't just cosmetic, - * without a reset, iteration on this cursor won't start at the - * beginning/end of the table. - */ - APPLY_CG(ctable, reset); - } else { - WT_ERR(ret); - - for (i = 1; i < WT_COLGROUPS(ctable->table); i++, cp++) { - (*cp)->recno = primary->recno; - WT_ERR((*cp)->insert(*cp)); - } - - WT_ERR(__apply_idx(ctable, offsetof(WT_CURSOR, insert), false)); - } - - /* - * Insert is the one cursor operation that doesn't end with the cursor - * pointing to an on-page item (except for column-store appends, where - * we are returning a key). That is, the application's cursor continues - * to reference the application's memory after a successful cursor call, - * which isn't true anywhere else. We don't want to have to explain that - * scoping corner case, so we reset the application's cursor so it can - * free the referenced memory and continue on without risking subsequent - * core dumps. - */ - F_CLR(primary, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET); - if (F_ISSET(primary, WT_CURSTD_APPEND)) - F_SET(primary, WT_CURSTD_KEY_EXT); - -err: CURSOR_UPDATE_API_END(session, ret); - return (ret); + WT_CURSOR *primary, **cp; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; + uint32_t flag_orig; + u_int i; + + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_UPDATE_API_CALL(cursor, session, insert); + WT_ERR(__curtable_open_indices(ctable)); + + /* + * Split out the first insert, it may be allocating a recno. + * + * If the table has indices, we also need to know whether this record + * is replacing an existing record so that the existing index entries + * can be removed. We discover if this is an overwrite by configuring + * the primary cursor for no-overwrite, and checking if the insert + * detects a duplicate key. + */ + cp = ctable->cg_cursors; + primary = *cp++; + + flag_orig = F_MASK(primary, WT_CURSTD_OVERWRITE); + if (ctable->table->nindices > 0) + F_CLR(primary, WT_CURSTD_OVERWRITE); + ret = primary->insert(primary); + + /* + * !!! + * WT_CURSOR.insert clears the set internally/externally flags + * but doesn't touch the items. We could make a copy each time + * for overwrite cursors, but for now we just reset the flags. + */ + F_SET(primary, flag_orig | WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT); + + if (ret == WT_DUPLICATE_KEY && F_ISSET(cursor, WT_CURSTD_OVERWRITE)) { + WT_ERR(__curtable_update(cursor)); + + /* + * The cursor is no longer positioned. This isn't just cosmetic, without a reset, iteration + * on this cursor won't start at the beginning/end of the table. + */ + APPLY_CG(ctable, reset); + } else { + WT_ERR(ret); + + for (i = 1; i < WT_COLGROUPS(ctable->table); i++, cp++) { + (*cp)->recno = primary->recno; + WT_ERR((*cp)->insert(*cp)); + } + + WT_ERR(__apply_idx(ctable, offsetof(WT_CURSOR, insert), false)); + } + + /* + * Insert is the one cursor operation that doesn't end with the cursor pointing to an on-page + * item (except for column-store appends, where we are returning a key). That is, the + * application's cursor continues to reference the application's memory after a successful + * cursor call, which isn't true anywhere else. We don't want to have to explain that scoping + * corner case, so we reset the application's cursor so it can free the referenced memory and + * continue on without risking subsequent core dumps. + */ + F_CLR(primary, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET); + if (F_ISSET(primary, WT_CURSTD_APPEND)) + F_SET(primary, WT_CURSTD_KEY_EXT); + +err: + CURSOR_UPDATE_API_END(session, ret); + return (ret); } /* * __curtable_update -- - * WT_CURSOR->update method for the table cursor type. + * WT_CURSOR->update method for the table cursor type. */ static int __curtable_update(WT_CURSOR *cursor) { - WT_CURSOR_TABLE *ctable; - WT_DECL_ITEM(value_copy); - WT_DECL_RET; - WT_SESSION_IMPL *session; - - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_UPDATE_API_CALL(cursor, session, update); - WT_ERR(__curtable_open_indices(ctable)); - - /* - * If the table has indices, first delete any old index keys, then - * update the primary, then insert the new index keys. This is - * complicated by the fact that we need the old value to generate the - * old index keys, so we make a temporary copy of the new value. - */ - if (ctable->table->nindices > 0) { - WT_ERR(__wt_scr_alloc( - session, ctable->cg_cursors[0]->value.size, &value_copy)); - WT_ERR(__wt_schema_project_merge(session, - ctable->cg_cursors, ctable->plan, - cursor->value_format, value_copy)); - APPLY_CG(ctable, search); - - /* Remove only if the key exists. */ - if (ret == 0) { - WT_ERR(__apply_idx(ctable, - offsetof(WT_CURSOR, remove), true)); - WT_ERR(__wt_schema_project_slice(session, - ctable->cg_cursors, ctable->plan, 0, - cursor->value_format, value_copy)); - } else - WT_ERR_NOTFOUND_OK(ret); - } - - APPLY_CG(ctable, update); - WT_ERR(ret); - - if (ctable->table->nindices > 0) - WT_ERR(__apply_idx(ctable, offsetof(WT_CURSOR, insert), true)); - -err: CURSOR_UPDATE_API_END(session, ret); - __wt_scr_free(session, &value_copy); - return (ret); + WT_CURSOR_TABLE *ctable; + WT_DECL_ITEM(value_copy); + WT_DECL_RET; + WT_SESSION_IMPL *session; + + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_UPDATE_API_CALL(cursor, session, update); + WT_ERR(__curtable_open_indices(ctable)); + + /* + * If the table has indices, first delete any old index keys, then update the primary, then + * insert the new index keys. This is complicated by the fact that we need the old value to + * generate the old index keys, so we make a temporary copy of the new value. + */ + if (ctable->table->nindices > 0) { + WT_ERR(__wt_scr_alloc(session, ctable->cg_cursors[0]->value.size, &value_copy)); + WT_ERR(__wt_schema_project_merge( + session, ctable->cg_cursors, ctable->plan, cursor->value_format, value_copy)); + APPLY_CG(ctable, search); + + /* Remove only if the key exists. */ + if (ret == 0) { + WT_ERR(__apply_idx(ctable, offsetof(WT_CURSOR, remove), true)); + WT_ERR(__wt_schema_project_slice( + session, ctable->cg_cursors, ctable->plan, 0, cursor->value_format, value_copy)); + } else + WT_ERR_NOTFOUND_OK(ret); + } + + APPLY_CG(ctable, update); + WT_ERR(ret); + + if (ctable->table->nindices > 0) + WT_ERR(__apply_idx(ctable, offsetof(WT_CURSOR, insert), true)); + +err: + CURSOR_UPDATE_API_END(session, ret); + __wt_scr_free(session, &value_copy); + return (ret); } /* * __curtable_remove -- - * WT_CURSOR->remove method for the table cursor type. + * WT_CURSOR->remove method for the table cursor type. */ static int __curtable_remove(WT_CURSOR *cursor) { - WT_CURSOR *primary; - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; - bool positioned; - - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_REMOVE_API_CALL(cursor, session, NULL); - WT_ERR(__curtable_open_indices(ctable)); - - /* Check if the cursor was positioned. */ - primary = *ctable->cg_cursors; - positioned = F_ISSET(primary, WT_CURSTD_KEY_INT); - - /* Find the old record so it can be removed from indices */ - if (ctable->table->nindices > 0) { - APPLY_CG(ctable, search); - if (ret == WT_NOTFOUND) - goto notfound; - WT_ERR(ret); - WT_ERR(__apply_idx(ctable, offsetof(WT_CURSOR, remove), false)); - } - - APPLY_CG(ctable, remove); - if (ret == WT_NOTFOUND) - goto notfound; - WT_ERR(ret); + WT_CURSOR *primary; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; + bool positioned; + + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_REMOVE_API_CALL(cursor, session, NULL); + WT_ERR(__curtable_open_indices(ctable)); + + /* Check if the cursor was positioned. */ + primary = *ctable->cg_cursors; + positioned = F_ISSET(primary, WT_CURSTD_KEY_INT); + + /* Find the old record so it can be removed from indices */ + if (ctable->table->nindices > 0) { + APPLY_CG(ctable, search); + if (ret == WT_NOTFOUND) + goto notfound; + WT_ERR(ret); + WT_ERR(__apply_idx(ctable, offsetof(WT_CURSOR, remove), false)); + } + + APPLY_CG(ctable, remove); + if (ret == WT_NOTFOUND) + goto notfound; + WT_ERR(ret); notfound: - /* - * If the cursor is configured to overwrite and the record is not found, - * that is exactly what we want. - */ - if (ret == WT_NOTFOUND && F_ISSET(primary, WT_CURSTD_OVERWRITE)) - ret = 0; - - /* - * If the cursor was positioned, it stays positioned with a key but no - * no value, otherwise, there's no position, key or value. This isn't - * just cosmetic, without a reset, iteration on this cursor won't start - * at the beginning/end of the table. - */ - F_CLR(primary, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET); - if (positioned) - F_SET(primary, WT_CURSTD_KEY_INT); - else - APPLY_CG(ctable, reset); - -err: CURSOR_UPDATE_API_END(session, ret); - return (ret); + /* + * If the cursor is configured to overwrite and the record is not found, that is exactly what we + * want. + */ + if (ret == WT_NOTFOUND && F_ISSET(primary, WT_CURSTD_OVERWRITE)) + ret = 0; + + /* + * If the cursor was positioned, it stays positioned with a key but no no value, otherwise, + * there's no position, key or value. This isn't just cosmetic, without a reset, iteration on + * this cursor won't start at the beginning/end of the table. + */ + F_CLR(primary, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET); + if (positioned) + F_SET(primary, WT_CURSTD_KEY_INT); + else + APPLY_CG(ctable, reset); + +err: + CURSOR_UPDATE_API_END(session, ret); + return (ret); } /* * __curtable_reserve -- - * WT_CURSOR->reserve method for the table cursor type. + * WT_CURSOR->reserve method for the table cursor type. */ static int __curtable_reserve(WT_CURSOR *cursor) { - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; - - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_UPDATE_API_CALL(cursor, session, update); - - /* - * We don't have to open the indices here, but it makes the code similar - * to other cursor functions, and it's odd for a reserve call to succeed - * but the subsequent update fail opening indices. - * - * Check for a transaction before index open, opening the indices will - * start a transaction if one isn't running. - */ - WT_ERR(__wt_txn_context_check(session, true)); - WT_ERR(__curtable_open_indices(ctable)); - - /* Reserve in column groups, ignore indices. */ - APPLY_CG(ctable, reserve); - -err: CURSOR_UPDATE_API_END(session, ret); - - /* - * The application might do a WT_CURSOR.get_value call when we return, - * so we need a value and the underlying functions didn't set one up. - * For various reasons, those functions may not have done a search and - * any previous value in the cursor might race with WT_CURSOR.reserve - * (and in cases like LSM, the reserve never encountered the original - * key). For simplicity, repeat the search here. - */ - return (ret == 0 ? cursor->search(cursor) : ret); + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; + + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_UPDATE_API_CALL(cursor, session, update); + + /* + * We don't have to open the indices here, but it makes the code similar + * to other cursor functions, and it's odd for a reserve call to succeed + * but the subsequent update fail opening indices. + * + * Check for a transaction before index open, opening the indices will + * start a transaction if one isn't running. + */ + WT_ERR(__wt_txn_context_check(session, true)); + WT_ERR(__curtable_open_indices(ctable)); + + /* Reserve in column groups, ignore indices. */ + APPLY_CG(ctable, reserve); + +err: + CURSOR_UPDATE_API_END(session, ret); + + /* + * The application might do a WT_CURSOR.get_value call when we return, + * so we need a value and the underlying functions didn't set one up. + * For various reasons, those functions may not have done a search and + * any previous value in the cursor might race with WT_CURSOR.reserve + * (and in cases like LSM, the reserve never encountered the original + * key). For simplicity, repeat the search here. + */ + return (ret == 0 ? cursor->search(cursor) : ret); } /* * __wt_table_range_truncate -- - * Truncate of a cursor range, table implementation. + * Truncate of a cursor range, table implementation. */ int __wt_table_range_truncate(WT_CURSOR_TABLE *start, WT_CURSOR_TABLE *stop) { - WT_CURSOR *wt_start, *wt_stop; - WT_CURSOR_TABLE *ctable; - WT_DECL_ITEM(key); - WT_DECL_RET; - WT_ITEM raw; - WT_SESSION_IMPL *session; - u_int i; - int cmp; - - ctable = (start != NULL) ? start : stop; - session = (WT_SESSION_IMPL *)ctable->iface.session; - wt_start = &start->iface; - wt_stop = &stop->iface; - - /* Open any indices. */ - WT_RET(__curtable_open_indices(ctable)); - WT_RET(__wt_scr_alloc(session, 128, &key)); - WT_STAT_DATA_INCR(session, cursor_truncate); - - /* - * Step through the cursor range, removing the index entries. - * - * If there are indices, copy the key we're using to step through the - * cursor range (so we can reset the cursor to its original position), - * then remove all of the index records in the truncated range. Copy - * the raw key because the memory is only valid until the cursor moves. - */ - if (ctable->table->nindices > 0) { - if (start == NULL) { - WT_ERR(__wt_cursor_get_raw_key(wt_stop, &raw)); - WT_ERR(__wt_buf_set(session, key, raw.data, raw.size)); - - do { - APPLY_CG(stop, search); - WT_ERR(ret); - WT_ERR(__apply_idx( - stop, offsetof(WT_CURSOR, remove), false)); - } while ((ret = wt_stop->prev(wt_stop)) == 0); - WT_ERR_NOTFOUND_OK(ret); - - __wt_cursor_set_raw_key(wt_stop, key); - APPLY_CG(stop, search); - } else { - WT_ERR(__wt_cursor_get_raw_key(wt_start, &raw)); - WT_ERR(__wt_buf_set(session, key, raw.data, raw.size)); - - cmp = -1; - do { - APPLY_CG(start, search); - WT_ERR(ret); - WT_ERR(__apply_idx( - start, offsetof(WT_CURSOR, remove), false)); - if (stop != NULL) - WT_ERR(wt_start->compare( - wt_start, wt_stop, - &cmp)); - } while (cmp < 0 && - (ret = wt_start->next(wt_start)) == 0); - WT_ERR_NOTFOUND_OK(ret); - - __wt_cursor_set_raw_key(wt_start, key); - APPLY_CG(start, search); - } - } - - /* Truncate the column groups. */ - for (i = 0; i < WT_COLGROUPS(ctable->table); i++) - WT_ERR(__wt_range_truncate( - (start == NULL) ? NULL : start->cg_cursors[i], - (stop == NULL) ? NULL : stop->cg_cursors[i])); - -err: __wt_scr_free(session, &key); - return (ret); + WT_CURSOR *wt_start, *wt_stop; + WT_CURSOR_TABLE *ctable; + WT_DECL_ITEM(key); + WT_DECL_RET; + WT_ITEM raw; + WT_SESSION_IMPL *session; + u_int i; + int cmp; + + ctable = (start != NULL) ? start : stop; + session = (WT_SESSION_IMPL *)ctable->iface.session; + wt_start = &start->iface; + wt_stop = &stop->iface; + + /* Open any indices. */ + WT_RET(__curtable_open_indices(ctable)); + WT_RET(__wt_scr_alloc(session, 128, &key)); + WT_STAT_DATA_INCR(session, cursor_truncate); + + /* + * Step through the cursor range, removing the index entries. + * + * If there are indices, copy the key we're using to step through the + * cursor range (so we can reset the cursor to its original position), + * then remove all of the index records in the truncated range. Copy + * the raw key because the memory is only valid until the cursor moves. + */ + if (ctable->table->nindices > 0) { + if (start == NULL) { + WT_ERR(__wt_cursor_get_raw_key(wt_stop, &raw)); + WT_ERR(__wt_buf_set(session, key, raw.data, raw.size)); + + do { + APPLY_CG(stop, search); + WT_ERR(ret); + WT_ERR(__apply_idx(stop, offsetof(WT_CURSOR, remove), false)); + } while ((ret = wt_stop->prev(wt_stop)) == 0); + WT_ERR_NOTFOUND_OK(ret); + + __wt_cursor_set_raw_key(wt_stop, key); + APPLY_CG(stop, search); + } else { + WT_ERR(__wt_cursor_get_raw_key(wt_start, &raw)); + WT_ERR(__wt_buf_set(session, key, raw.data, raw.size)); + + cmp = -1; + do { + APPLY_CG(start, search); + WT_ERR(ret); + WT_ERR(__apply_idx(start, offsetof(WT_CURSOR, remove), false)); + if (stop != NULL) + WT_ERR(wt_start->compare(wt_start, wt_stop, &cmp)); + } while (cmp < 0 && (ret = wt_start->next(wt_start)) == 0); + WT_ERR_NOTFOUND_OK(ret); + + __wt_cursor_set_raw_key(wt_start, key); + APPLY_CG(start, search); + } + } + + /* Truncate the column groups. */ + for (i = 0; i < WT_COLGROUPS(ctable->table); i++) + WT_ERR(__wt_range_truncate((start == NULL) ? NULL : start->cg_cursors[i], + (stop == NULL) ? NULL : stop->cg_cursors[i])); + +err: + __wt_scr_free(session, &key); + return (ret); } /* * __curtable_close -- - * WT_CURSOR->close method for the table cursor type. + * WT_CURSOR->close method for the table cursor type. */ static int __curtable_close(WT_CURSOR *cursor) { - WT_CURSOR **cp; - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_SESSION_IMPL *session; - u_int i; - - ctable = (WT_CURSOR_TABLE *)cursor; - JOINABLE_CURSOR_API_CALL_PREPARE_ALLOWED(cursor, session, close, NULL); + WT_CURSOR **cp; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; + u_int i; + + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_API_CALL_PREPARE_ALLOWED(cursor, session, close, NULL); err: - if (ctable->cg_cursors != NULL) - for (i = 0, cp = ctable->cg_cursors; - i < WT_COLGROUPS(ctable->table); i++, cp++) - if (*cp != NULL) { - WT_TRET((*cp)->close(*cp)); - *cp = NULL; - } - - if (ctable->idx_cursors != NULL) - for (i = 0, cp = ctable->idx_cursors; - i < ctable->table->nindices; i++, cp++) - if (*cp != NULL) { - WT_TRET((*cp)->close(*cp)); - *cp = NULL; - } - - if (ctable->plan != ctable->table->plan) - __wt_free(session, ctable->plan); - if (ctable->cfg != NULL) { - for (i = 0; ctable->cfg[i] != NULL; ++i) - __wt_free(session, ctable->cfg[i]); - __wt_free(session, ctable->cfg); - } - if (cursor->value_format != ctable->table->value_format) - __wt_free(session, cursor->value_format); - __wt_free(session, ctable->cg_cursors); - __wt_free(session, ctable->cg_valcopy); - __wt_free(session, ctable->idx_cursors); - - WT_TRET(__wt_schema_release_table(session, &ctable->table)); - /* The URI is owned by the table. */ - cursor->internal_uri = NULL; - __wt_cursor_close(cursor); - - API_END_RET(session, ret); + if (ctable->cg_cursors != NULL) + for (i = 0, cp = ctable->cg_cursors; i < WT_COLGROUPS(ctable->table); i++, cp++) + if (*cp != NULL) { + WT_TRET((*cp)->close(*cp)); + *cp = NULL; + } + + if (ctable->idx_cursors != NULL) + for (i = 0, cp = ctable->idx_cursors; i < ctable->table->nindices; i++, cp++) + if (*cp != NULL) { + WT_TRET((*cp)->close(*cp)); + *cp = NULL; + } + + if (ctable->plan != ctable->table->plan) + __wt_free(session, ctable->plan); + if (ctable->cfg != NULL) { + for (i = 0; ctable->cfg[i] != NULL; ++i) + __wt_free(session, ctable->cfg[i]); + __wt_free(session, ctable->cfg); + } + if (cursor->value_format != ctable->table->value_format) + __wt_free(session, cursor->value_format); + __wt_free(session, ctable->cg_cursors); + __wt_free(session, ctable->cg_valcopy); + __wt_free(session, ctable->idx_cursors); + + WT_TRET(__wt_schema_release_table(session, &ctable->table)); + /* The URI is owned by the table. */ + cursor->internal_uri = NULL; + __wt_cursor_close(cursor); + + API_END_RET(session, ret); } /* * __curtable_complete -- - * Return failure if the table is not yet fully created. + * Return failure if the table is not yet fully created. */ static int __curtable_complete(WT_SESSION_IMPL *session, WT_TABLE *table) { - bool complete; - - if (table->cg_complete) - return (0); - - /* If the table is incomplete, wait on the table lock and recheck. */ - WT_WITH_TABLE_READ_LOCK(session, complete = table->cg_complete); - if (!complete) - WT_RET_MSG(session, EINVAL, - "'%s' not available until all column groups are created", - table->iface.name); - return (0); + bool complete; + + if (table->cg_complete) + return (0); + + /* If the table is incomplete, wait on the table lock and recheck. */ + WT_WITH_TABLE_READ_LOCK(session, complete = table->cg_complete); + if (!complete) + WT_RET_MSG(session, EINVAL, "'%s' not available until all column groups are created", + table->iface.name); + return (0); } /* * __curtable_open_colgroups -- - * Open cursors on column groups for a table cursor. + * Open cursors on column groups for a table cursor. */ static int __curtable_open_colgroups(WT_CURSOR_TABLE *ctable, const char *cfg_arg[]) { - WT_CURSOR **cp; - WT_SESSION_IMPL *session; - WT_TABLE *table; - /* - * Underlying column groups are always opened without dump or readonly, - * and only the primary is opened with next_random. - */ - const char *cfg[] = { - cfg_arg[0], cfg_arg[1], "dump=\"\",readonly=0", NULL, NULL - }; - u_int i; - - session = (WT_SESSION_IMPL *)ctable->iface.session; - table = ctable->table; - - WT_RET(__curtable_complete(session, table)); /* completeness check */ - - WT_RET(__wt_calloc_def(session, - WT_COLGROUPS(table), &ctable->cg_cursors)); - WT_RET(__wt_calloc_def(session, - WT_COLGROUPS(table), &ctable->cg_valcopy)); - - for (i = 0, cp = ctable->cg_cursors; - i < WT_COLGROUPS(table); - i++, cp++) { - WT_RET(__wt_open_cursor(session, table->cgroups[i]->source, - &ctable->iface, cfg, cp)); - cfg[3] = "next_random=false"; - } - return (0); + WT_CURSOR **cp; + WT_SESSION_IMPL *session; + WT_TABLE *table; + /* + * Underlying column groups are always opened without dump or readonly, and only the primary is + * opened with next_random. + */ + const char *cfg[] = {cfg_arg[0], cfg_arg[1], "dump=\"\",readonly=0", NULL, NULL}; + u_int i; + + session = (WT_SESSION_IMPL *)ctable->iface.session; + table = ctable->table; + + WT_RET(__curtable_complete(session, table)); /* completeness check */ + + WT_RET(__wt_calloc_def(session, WT_COLGROUPS(table), &ctable->cg_cursors)); + WT_RET(__wt_calloc_def(session, WT_COLGROUPS(table), &ctable->cg_valcopy)); + + for (i = 0, cp = ctable->cg_cursors; i < WT_COLGROUPS(table); i++, cp++) { + WT_RET(__wt_open_cursor(session, table->cgroups[i]->source, &ctable->iface, cfg, cp)); + cfg[3] = "next_random=false"; + } + return (0); } /* * __curtable_open_indices -- - * Open cursors on indices for a table cursor. + * Open cursors on indices for a table cursor. */ static int __curtable_open_indices(WT_CURSOR_TABLE *ctable) { - WT_CURSOR **cp, *primary; - WT_SESSION_IMPL *session; - WT_TABLE *table; - u_int i; - - session = (WT_SESSION_IMPL *)ctable->iface.session; - table = ctable->table; - - WT_RET(__wt_schema_open_indices(session, table)); - if (table->nindices == 0 || ctable->idx_cursors != NULL) - return (0); - - /* Check for bulk cursors. */ - primary = *ctable->cg_cursors; - if (F_ISSET(primary, WT_CURSTD_BULK)) - WT_RET_MSG(session, ENOTSUP, - "Bulk load is not supported for tables with indices"); - - WT_RET(__wt_calloc_def(session, table->nindices, &ctable->idx_cursors)); - for (i = 0, cp = ctable->idx_cursors; i < table->nindices; i++, cp++) - WT_RET(__wt_open_cursor(session, table->indices[i]->source, - &ctable->iface, ctable->cfg, cp)); - return (0); + WT_CURSOR **cp, *primary; + WT_SESSION_IMPL *session; + WT_TABLE *table; + u_int i; + + session = (WT_SESSION_IMPL *)ctable->iface.session; + table = ctable->table; + + WT_RET(__wt_schema_open_indices(session, table)); + if (table->nindices == 0 || ctable->idx_cursors != NULL) + return (0); + + /* Check for bulk cursors. */ + primary = *ctable->cg_cursors; + if (F_ISSET(primary, WT_CURSTD_BULK)) + WT_RET_MSG(session, ENOTSUP, "Bulk load is not supported for tables with indices"); + + WT_RET(__wt_calloc_def(session, table->nindices, &ctable->idx_cursors)); + for (i = 0, cp = ctable->idx_cursors; i < table->nindices; i++, cp++) + WT_RET( + __wt_open_cursor(session, table->indices[i]->source, &ctable->iface, ctable->cfg, cp)); + return (0); } /* * __wt_curtable_open -- - * WT_SESSION->open_cursor method for table cursors. + * WT_SESSION->open_cursor method for table cursors. */ int -__wt_curtable_open(WT_SESSION_IMPL *session, - const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) +__wt_curtable_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], + WT_CURSOR **cursorp) { - WT_CURSOR_STATIC_INIT(iface, - __wt_curtable_get_key, /* get-key */ - __wt_curtable_get_value, /* get-value */ - __wt_curtable_set_key, /* set-key */ - __wt_curtable_set_value, /* set-value */ - __curtable_compare, /* compare */ - __wt_cursor_equals, /* equals */ - __curtable_next, /* next */ - __curtable_prev, /* prev */ - __curtable_reset, /* reset */ - __curtable_search, /* search */ - __curtable_search_near, /* search-near */ - __curtable_insert, /* insert */ - __wt_cursor_modify_notsup, /* modify */ - __curtable_update, /* update */ - __curtable_remove, /* remove */ - __curtable_reserve, /* reserve */ - __wt_cursor_reconfigure, /* reconfigure */ - __wt_cursor_notsup, /* cache */ - __wt_cursor_reopen_notsup, /* reopen */ - __curtable_close); /* close */ - WT_CONFIG_ITEM cval; - WT_CURSOR *cursor; - WT_CURSOR_TABLE *ctable; - WT_DECL_ITEM(tmp); - WT_DECL_RET; - WT_TABLE *table; - size_t size; - int cfg_cnt; - const char *tablename, *columns; - - WT_STATIC_ASSERT(offsetof(WT_CURSOR_TABLE, iface) == 0); - - tablename = uri; - WT_PREFIX_SKIP_REQUIRED(session, tablename, "table:"); - columns = strchr(tablename, '('); - if (columns == NULL) - WT_RET(__wt_schema_get_table_uri( - session, uri, false, 0, &table)); - else { - size = WT_PTRDIFF(columns, tablename); - WT_RET(__wt_schema_get_table( - session, tablename, size, false, 0, &table)); - } - - WT_RET(__curtable_complete(session, table)); /* completeness check */ - - if (table->is_simple) { - /* Just return a cursor on the underlying data source. */ - ret = __wt_open_cursor(session, - table->cgroups[0]->source, NULL, cfg, cursorp); - - WT_TRET(__wt_schema_release_table(session, &table)); - if (ret == 0) { - /* Fix up the public URI to match what was passed in. */ - cursor = *cursorp; - __wt_free(session, cursor->uri); - WT_TRET(__wt_strdup(session, uri, &cursor->uri)); - } - return (ret); - } - - WT_RET(__wt_calloc_one(session, &ctable)); - cursor = (WT_CURSOR *)ctable; - *cursor = iface; - cursor->session = (WT_SESSION *)session; - cursor->internal_uri = table->iface.name; - cursor->key_format = table->key_format; - cursor->value_format = table->value_format; - - ctable->table = table; - ctable->plan = table->plan; - - /* Handle projections. */ - WT_ERR(__wt_scr_alloc(session, 0, &tmp)); - if (columns != NULL) { - WT_ERR(__wt_struct_reformat(session, table, - columns, strlen(columns), NULL, false, tmp)); - WT_ERR(__wt_strndup( - session, tmp->data, tmp->size, &cursor->value_format)); - - WT_ERR(__wt_buf_init(session, tmp, 0)); - WT_ERR(__wt_struct_plan(session, table, - columns, strlen(columns), false, tmp)); - WT_ERR(__wt_strndup( - session, tmp->data, tmp->size, &ctable->plan)); - } - - /* - * random_retrieval - * Random retrieval cursors only support next, reset and close. - */ - WT_ERR(__wt_config_gets_def(session, cfg, "next_random", 0, &cval)); - if (cval.val != 0) { - __wt_cursor_set_notsup(cursor); - cursor->next = __curtable_next_random; - cursor->reset = __curtable_reset; - } - - WT_ERR(__wt_cursor_init( - cursor, cursor->internal_uri, owner, cfg, cursorp)); - - if (F_ISSET(cursor, WT_CURSTD_DUMP_JSON)) - WT_ERR(__wt_json_column_init( - cursor, uri, table->key_format, NULL, &table->colconf)); - - /* - * Open the colgroup cursors immediately: we're going to need them for - * any operation. We defer opening index cursors until we need them - * for an update. Note that this must come after the call to - * __wt_cursor_init: the table cursor must already be on the list of - * session cursors or we can't work out where to put the colgroup - * cursor(s). - */ - WT_ERR(__curtable_open_colgroups(ctable, cfg)); - - /* - * We'll need to squirrel away a copy of the cursor configuration for - * if/when we open indices. - * - * cfg[0] is the baseline configuration for the cursor open and we can - * acquire another copy from the configuration structures, so it would - * be reasonable not to copy it here: but I'd rather be safe than sorry. - * - * cfg[1] is the application configuration. - * - * Underlying indices are always opened without dump or readonly; that - * information is appended to cfg[1] so later "fast" configuration calls - * (checking only cfg[0] and cfg[1]) work. I don't expect to see more - * than two configuration strings here, but it's written to compact into - * two configuration strings, a copy of cfg[0] and the rest in cfg[1]. - */ - WT_ERR(__wt_calloc_def(session, 3, &ctable->cfg)); - WT_ERR(__wt_strdup(session, cfg[0], &ctable->cfg[0])); - WT_ERR(__wt_buf_set(session, tmp, "", 0)); - for (cfg_cnt = 1; cfg[cfg_cnt] != NULL; ++cfg_cnt) - WT_ERR(__wt_buf_catfmt(session, tmp, "%s,", cfg[cfg_cnt])); - WT_ERR(__wt_buf_catfmt(session, tmp, "dump=\"\",readonly=0")); - WT_ERR(__wt_strdup(session, tmp->data, &ctable->cfg[1])); - - if (0) { -err: if (*cursorp != NULL) { - /* - * When a dump cursor is opened, then *cursorp, not - * cursor, is the dump cursor. Close the dump cursor, - * and the table cursor will be closed as its child. - */ - cursor = *cursorp; - *cursorp = NULL; - } - WT_TRET(cursor->close(cursor)); - } - - __wt_scr_free(session, &tmp); - return (ret); + WT_CURSOR_STATIC_INIT(iface, __wt_curtable_get_key, /* get-key */ + __wt_curtable_get_value, /* get-value */ + __wt_curtable_set_key, /* set-key */ + __wt_curtable_set_value, /* set-value */ + __curtable_compare, /* compare */ + __wt_cursor_equals, /* equals */ + __curtable_next, /* next */ + __curtable_prev, /* prev */ + __curtable_reset, /* reset */ + __curtable_search, /* search */ + __curtable_search_near, /* search-near */ + __curtable_insert, /* insert */ + __wt_cursor_modify_notsup, /* modify */ + __curtable_update, /* update */ + __curtable_remove, /* remove */ + __curtable_reserve, /* reserve */ + __wt_cursor_reconfigure, /* reconfigure */ + __wt_cursor_notsup, /* cache */ + __wt_cursor_reopen_notsup, /* reopen */ + __curtable_close); /* close */ + WT_CONFIG_ITEM cval; + WT_CURSOR *cursor; + WT_CURSOR_TABLE *ctable; + WT_DECL_ITEM(tmp); + WT_DECL_RET; + WT_TABLE *table; + size_t size; + int cfg_cnt; + const char *tablename, *columns; + + WT_STATIC_ASSERT(offsetof(WT_CURSOR_TABLE, iface) == 0); + + tablename = uri; + WT_PREFIX_SKIP_REQUIRED(session, tablename, "table:"); + columns = strchr(tablename, '('); + if (columns == NULL) + WT_RET(__wt_schema_get_table_uri(session, uri, false, 0, &table)); + else { + size = WT_PTRDIFF(columns, tablename); + WT_RET(__wt_schema_get_table(session, tablename, size, false, 0, &table)); + } + + WT_RET(__curtable_complete(session, table)); /* completeness check */ + + if (table->is_simple) { + /* Just return a cursor on the underlying data source. */ + ret = __wt_open_cursor(session, table->cgroups[0]->source, NULL, cfg, cursorp); + + WT_TRET(__wt_schema_release_table(session, &table)); + if (ret == 0) { + /* Fix up the public URI to match what was passed in. */ + cursor = *cursorp; + __wt_free(session, cursor->uri); + WT_TRET(__wt_strdup(session, uri, &cursor->uri)); + } + return (ret); + } + + WT_RET(__wt_calloc_one(session, &ctable)); + cursor = (WT_CURSOR *)ctable; + *cursor = iface; + cursor->session = (WT_SESSION *)session; + cursor->internal_uri = table->iface.name; + cursor->key_format = table->key_format; + cursor->value_format = table->value_format; + + ctable->table = table; + ctable->plan = table->plan; + + /* Handle projections. */ + WT_ERR(__wt_scr_alloc(session, 0, &tmp)); + if (columns != NULL) { + WT_ERR(__wt_struct_reformat(session, table, columns, strlen(columns), NULL, false, tmp)); + WT_ERR(__wt_strndup(session, tmp->data, tmp->size, &cursor->value_format)); + + WT_ERR(__wt_buf_init(session, tmp, 0)); + WT_ERR(__wt_struct_plan(session, table, columns, strlen(columns), false, tmp)); + WT_ERR(__wt_strndup(session, tmp->data, tmp->size, &ctable->plan)); + } + + /* + * random_retrieval Random retrieval cursors only support next, reset and close. + */ + WT_ERR(__wt_config_gets_def(session, cfg, "next_random", 0, &cval)); + if (cval.val != 0) { + __wt_cursor_set_notsup(cursor); + cursor->next = __curtable_next_random; + cursor->reset = __curtable_reset; + } + + WT_ERR(__wt_cursor_init(cursor, cursor->internal_uri, owner, cfg, cursorp)); + + if (F_ISSET(cursor, WT_CURSTD_DUMP_JSON)) + WT_ERR(__wt_json_column_init(cursor, uri, table->key_format, NULL, &table->colconf)); + + /* + * Open the colgroup cursors immediately: we're going to need them for + * any operation. We defer opening index cursors until we need them + * for an update. Note that this must come after the call to + * __wt_cursor_init: the table cursor must already be on the list of + * session cursors or we can't work out where to put the colgroup + * cursor(s). + */ + WT_ERR(__curtable_open_colgroups(ctable, cfg)); + + /* + * We'll need to squirrel away a copy of the cursor configuration for + * if/when we open indices. + * + * cfg[0] is the baseline configuration for the cursor open and we can + * acquire another copy from the configuration structures, so it would + * be reasonable not to copy it here: but I'd rather be safe than sorry. + * + * cfg[1] is the application configuration. + * + * Underlying indices are always opened without dump or readonly; that + * information is appended to cfg[1] so later "fast" configuration calls + * (checking only cfg[0] and cfg[1]) work. I don't expect to see more + * than two configuration strings here, but it's written to compact into + * two configuration strings, a copy of cfg[0] and the rest in cfg[1]. + */ + WT_ERR(__wt_calloc_def(session, 3, &ctable->cfg)); + WT_ERR(__wt_strdup(session, cfg[0], &ctable->cfg[0])); + WT_ERR(__wt_buf_set(session, tmp, "", 0)); + for (cfg_cnt = 1; cfg[cfg_cnt] != NULL; ++cfg_cnt) + WT_ERR(__wt_buf_catfmt(session, tmp, "%s,", cfg[cfg_cnt])); + WT_ERR(__wt_buf_catfmt(session, tmp, "dump=\"\",readonly=0")); + WT_ERR(__wt_strdup(session, tmp->data, &ctable->cfg[1])); + + if (0) { +err: + if (*cursorp != NULL) { + /* + * When a dump cursor is opened, then *cursorp, not cursor, is the dump cursor. Close + * the dump cursor, and the table cursor will be closed as its child. + */ + cursor = *cursorp; + *cursorp = NULL; + } + WT_TRET(cursor->close(cursor)); + } + + __wt_scr_free(session, &tmp); + return (ret); } |