summaryrefslogtreecommitdiff
path: root/src/cursor
diff options
context:
space:
mode:
Diffstat (limited to 'src/cursor')
-rw-r--r--src/cursor/cur_backup.c24
-rw-r--r--src/cursor/cur_file.c158
-rw-r--r--src/cursor/cur_index.c30
-rw-r--r--src/cursor/cur_join.c24
-rw-r--r--src/cursor/cur_json.c150
-rw-r--r--src/cursor/cur_log.c4
-rw-r--r--src/cursor/cur_metadata.c4
-rw-r--r--src/cursor/cur_stat.c5
-rw-r--r--src/cursor/cur_std.c8
-rw-r--r--src/cursor/cur_table.c60
10 files changed, 269 insertions, 198 deletions
diff --git a/src/cursor/cur_backup.c b/src/cursor/cur_backup.c
index 456aa2e0f02..61ced8d11e7 100644
--- a/src/cursor/cur_backup.c
+++ b/src/cursor/cur_backup.c
@@ -230,10 +230,10 @@ __backup_start(
* We are holding the checkpoint and schema locks so schema operations
* will not see the backup file list until it is complete and valid.
*/
- __wt_writelock(session, conn->hot_backup_lock);
+ __wt_writelock(session, &conn->hot_backup_lock);
conn->hot_backup = true;
conn->hot_backup_list = NULL;
- __wt_writeunlock(session, conn->hot_backup_lock);
+ __wt_writeunlock(session, &conn->hot_backup_lock);
/* We're the lock holder, we own cleanup. */
F_SET(cb, WT_CURBACKUP_LOCKER);
@@ -297,9 +297,9 @@ err: /* Close the hot backup file. */
if (ret == 0) {
WT_ASSERT(session, dest != NULL);
WT_TRET(__wt_fs_rename(session, WT_BACKUP_TMP, dest, false));
- __wt_writelock(session, conn->hot_backup_lock);
+ __wt_writelock(session, &conn->hot_backup_lock);
conn->hot_backup_list = cb->list;
- __wt_writeunlock(session, conn->hot_backup_lock);
+ __wt_writeunlock(session, &conn->hot_backup_lock);
}
return (ret);
@@ -319,9 +319,9 @@ __backup_stop(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb)
conn = S2C(session);
/* Release all btree names held by the backup. */
- __wt_writelock(session, conn->hot_backup_lock);
+ __wt_writelock(session, &conn->hot_backup_lock);
conn->hot_backup_list = NULL;
- __wt_writeunlock(session, conn->hot_backup_lock);
+ __wt_writeunlock(session, &conn->hot_backup_lock);
if (cb->list != NULL) {
for (i = 0; cb->list[i] != NULL; ++i)
__wt_free(session, cb->list[i]);
@@ -332,9 +332,9 @@ __backup_stop(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb)
WT_TRET(__wt_backup_file_remove(session));
/* Checkpoint deletion can proceed, as can the next hot backup. */
- __wt_writelock(session, conn->hot_backup_lock);
+ __wt_writelock(session, &conn->hot_backup_lock);
conn->hot_backup = false;
- __wt_writeunlock(session, conn->hot_backup_lock);
+ __wt_writeunlock(session, &conn->hot_backup_lock);
return (ret);
}
@@ -346,13 +346,9 @@ __backup_stop(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb)
static int
__backup_all(WT_SESSION_IMPL *session)
{
- WT_DECL_RET;
-
/* Build a list of the file objects that need to be copied. */
- WT_WITH_HANDLE_LIST_LOCK(session, ret =
- __wt_meta_apply_all(session, NULL, __backup_list_uri_append, NULL));
-
- return (ret);
+ return (__wt_meta_apply_all(
+ session, NULL, __backup_list_uri_append, NULL));
}
/*
diff --git a/src/cursor/cur_file.c b/src/cursor/cur_file.c
index 0ec917fbf95..205afb607c3 100644
--- a/src/cursor/cur_file.c
+++ b/src/cursor/cur_file.c
@@ -9,29 +9,6 @@
#include "wt_internal.h"
/*
- * WT_BTREE_CURSOR_SAVE_AND_RESTORE
- * Save the cursor's key/value data/size fields, call an underlying btree
- * function, and then consistently handle failure and success.
- */
-#define WT_BTREE_CURSOR_SAVE_AND_RESTORE(cursor, f, ret) do { \
- WT_ITEM __key_copy = (cursor)->key; \
- uint64_t __recno = (cursor)->recno; \
- WT_ITEM __value_copy = (cursor)->value; \
- if (((ret) = (f)) == 0) { \
- F_CLR(cursor, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT); \
- F_SET(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT); \
- } else { \
- if (F_ISSET(cursor, WT_CURSTD_KEY_EXT)) { \
- (cursor)->recno = __recno; \
- WT_ITEM_SET((cursor)->key, __key_copy); \
- } \
- if (F_ISSET(cursor, WT_CURSTD_VALUE_EXT)) \
- WT_ITEM_SET((cursor)->value, __value_copy); \
- F_CLR(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT); \
- } \
-} while (0)
-
-/*
* __curfile_compare --
* WT_CURSOR->compare method for the btree cursor type.
*/
@@ -109,9 +86,12 @@ __curfile_next(WT_CURSOR *cursor)
cbt = (WT_CURSOR_BTREE *)cursor;
CURSOR_API_CALL(cursor, session, next, cbt->btree);
- F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET);
- if ((ret = __wt_btcur_next(cbt, false)) == 0)
- F_SET(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT);
+ WT_ERR(__wt_btcur_next(cbt, false));
+
+ /* Next maintains a position, key and value. */
+ WT_ASSERT(session,
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == WT_CURSTD_KEY_INT &&
+ F_MASK(cursor, WT_CURSTD_VALUE_SET) == WT_CURSTD_VALUE_INT);
err: API_END_RET(session, ret);
}
@@ -131,9 +111,12 @@ __wt_curfile_next_random(WT_CURSOR *cursor)
cbt = (WT_CURSOR_BTREE *)cursor;
CURSOR_API_CALL(cursor, session, next, cbt->btree);
- F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET);
- if ((ret = __wt_btcur_next_random(cbt)) == 0)
- F_SET(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT);
+ WT_ERR(__wt_btcur_next_random(cbt));
+
+ /* Next-random maintains a position, key and value. */
+ WT_ASSERT(session,
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == WT_CURSTD_KEY_INT &&
+ F_MASK(cursor, WT_CURSTD_VALUE_SET) == WT_CURSTD_VALUE_INT);
err: API_END_RET(session, ret);
}
@@ -152,9 +135,12 @@ __curfile_prev(WT_CURSOR *cursor)
cbt = (WT_CURSOR_BTREE *)cursor;
CURSOR_API_CALL(cursor, session, prev, cbt->btree);
- F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET);
- if ((ret = __wt_btcur_prev(cbt, false)) == 0)
- F_SET(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT);
+ WT_ERR(__wt_btcur_prev(cbt, false));
+
+ /* Prev maintains a position, key and value. */
+ WT_ASSERT(session,
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == WT_CURSTD_KEY_INT &&
+ F_MASK(cursor, WT_CURSTD_VALUE_SET) == WT_CURSTD_VALUE_INT);
err: API_END_RET(session, ret);
}
@@ -175,7 +161,10 @@ __curfile_reset(WT_CURSOR *cursor)
ret = __wt_btcur_reset(cbt);
- F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET);
+ /* Reset maintains no position, key or value. */
+ WT_ASSERT(session,
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == 0 &&
+ F_MASK(cursor, WT_CURSTD_VALUE_SET) == 0);
err: API_END_RET(session, ret);
}
@@ -194,10 +183,15 @@ __curfile_search(WT_CURSOR *cursor)
cbt = (WT_CURSOR_BTREE *)cursor;
CURSOR_API_CALL(cursor, session, search, cbt->btree);
- WT_CURSOR_NEEDKEY(cursor);
+ WT_CURSOR_CHECKKEY(cursor);
WT_CURSOR_NOVALUE(cursor);
- WT_BTREE_CURSOR_SAVE_AND_RESTORE(cursor, __wt_btcur_search(cbt), ret);
+ WT_ERR(__wt_btcur_search(cbt));
+
+ /* Search maintains a position, key and value. */
+ WT_ASSERT(session,
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == WT_CURSTD_KEY_INT &&
+ F_MASK(cursor, WT_CURSTD_VALUE_SET) == WT_CURSTD_VALUE_INT);
err: API_END_RET(session, ret);
}
@@ -216,11 +210,15 @@ __curfile_search_near(WT_CURSOR *cursor, int *exact)
cbt = (WT_CURSOR_BTREE *)cursor;
CURSOR_API_CALL(cursor, session, search_near, cbt->btree);
- WT_CURSOR_NEEDKEY(cursor);
+ WT_CURSOR_CHECKKEY(cursor);
WT_CURSOR_NOVALUE(cursor);
- WT_BTREE_CURSOR_SAVE_AND_RESTORE(
- cursor, __wt_btcur_search_near(cbt, exact), ret);
+ WT_ERR(__wt_btcur_search_near(cbt, exact));
+
+ /* Search-near maintains a position, key and value. */
+ WT_ASSERT(session,
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == WT_CURSTD_KEY_INT &&
+ F_MASK(cursor, WT_CURSTD_VALUE_SET) == WT_CURSTD_VALUE_INT);
err: API_END_RET(session, ret);
}
@@ -238,38 +236,33 @@ __curfile_insert(WT_CURSOR *cursor)
cbt = (WT_CURSOR_BTREE *)cursor;
CURSOR_UPDATE_API_CALL(cursor, session, insert, cbt->btree);
+
if (!F_ISSET(cursor, WT_CURSTD_APPEND))
- WT_CURSOR_NEEDKEY(cursor);
- WT_CURSOR_NEEDVALUE(cursor);
+ WT_CURSOR_CHECKKEY(cursor);
+ WT_CURSOR_CHECKVALUE(cursor);
- WT_BTREE_CURSOR_SAVE_AND_RESTORE(cursor, __wt_btcur_insert(cbt), ret);
+ WT_ERR(__wt_btcur_insert(cbt));
/*
- * 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.
+ * Insert maintains no position, key or value (except for column-store
+ * appends, where we are returning a key).
*/
- if (ret == 0) {
- if (!F_ISSET(cursor, WT_CURSTD_APPEND))
- F_CLR(cursor, WT_CURSTD_KEY_INT);
- F_CLR(cursor, WT_CURSTD_VALUE_INT);
- }
+ WT_ASSERT(session,
+ (F_ISSET(cursor, WT_CURSTD_APPEND) &&
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == WT_CURSTD_KEY_INT) ||
+ (!F_ISSET(cursor, WT_CURSTD_APPEND) &&
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == 0));
err: CURSOR_UPDATE_API_END(session, ret);
return (ret);
}
/*
- * __curfile_update --
- * WT_CURSOR->update method for the btree cursor type.
+ * __wt_curfile_insert_check --
+ * WT_CURSOR->insert_check method for the btree cursor type.
*/
-static int
-__curfile_update(WT_CURSOR *cursor)
+int
+__wt_curfile_insert_check(WT_CURSOR *cursor)
{
WT_CURSOR_BTREE *cbt;
WT_DECL_RET;
@@ -278,21 +271,21 @@ __curfile_update(WT_CURSOR *cursor)
cbt = (WT_CURSOR_BTREE *)cursor;
CURSOR_UPDATE_API_CALL(cursor, session, update, cbt->btree);
- WT_CURSOR_NEEDKEY(cursor);
- WT_CURSOR_NEEDVALUE(cursor);
+ WT_CURSOR_CHECKKEY(cursor);
+ WT_CURSOR_NOVALUE(cursor);
- WT_BTREE_CURSOR_SAVE_AND_RESTORE(cursor, __wt_btcur_update(cbt), ret);
+ ret = __wt_btcur_insert_check(cbt);
err: CURSOR_UPDATE_API_END(session, ret);
return (ret);
}
/*
- * __wt_curfile_update_check --
- * WT_CURSOR->update_check method for the btree cursor type.
+ * __curfile_update --
+ * WT_CURSOR->update method for the btree cursor type.
*/
-int
-__wt_curfile_update_check(WT_CURSOR *cursor)
+static int
+__curfile_update(WT_CURSOR *cursor)
{
WT_CURSOR_BTREE *cbt;
WT_DECL_RET;
@@ -301,11 +294,15 @@ __wt_curfile_update_check(WT_CURSOR *cursor)
cbt = (WT_CURSOR_BTREE *)cursor;
CURSOR_UPDATE_API_CALL(cursor, session, update, cbt->btree);
- WT_CURSOR_NEEDKEY(cursor);
- WT_CURSOR_NOVALUE(cursor);
+ WT_CURSOR_CHECKKEY(cursor);
+ WT_CURSOR_CHECKVALUE(cursor);
- WT_BTREE_CURSOR_SAVE_AND_RESTORE(
- cursor, __wt_btcur_update_check(cbt), ret);
+ WT_ERR(__wt_btcur_update(cbt));
+
+ /* Update maintains a position, key and value. */
+ WT_ASSERT(session,
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == WT_CURSTD_KEY_INT &&
+ F_MASK(cursor, WT_CURSTD_VALUE_SET) == WT_CURSTD_VALUE_INT);
err: CURSOR_UPDATE_API_END(session, ret);
return (ret);
@@ -325,24 +322,21 @@ __curfile_remove(WT_CURSOR *cursor)
cbt = (WT_CURSOR_BTREE *)cursor;
CURSOR_REMOVE_API_CALL(cursor, session, cbt->btree);
- WT_CURSOR_NEEDKEY(cursor);
+ WT_CURSOR_CHECKKEY(cursor);
WT_CURSOR_NOVALUE(cursor);
- WT_BTREE_CURSOR_SAVE_AND_RESTORE(cursor, __wt_btcur_remove(cbt), ret);
+ WT_ERR(__wt_btcur_remove(cbt));
/*
- * After a successful remove, copy the key: the value is not available.
+ * Remove with a search-key is fire-and-forget, no position and no key.
+ * Remove starting from a position maintains the position and a key.
+ * We don't know which it was at this layer, so can only assert the key
+ * is not set at all, or internal. There's never a value.
*/
- if (ret == 0) {
- if (F_ISSET(cursor, WT_CURSTD_KEY_INT) &&
- !WT_DATA_IN_ITEM(&(cursor)->key)) {
- WT_ERR(__wt_buf_set(session, &cursor->key,
- cursor->key.data, cursor->key.size));
- F_CLR(cursor, WT_CURSTD_KEY_INT);
- F_SET(cursor, WT_CURSTD_KEY_EXT);
- }
- F_CLR(cursor, WT_CURSTD_VALUE_SET);
- }
+ WT_ASSERT(session,
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == 0 ||
+ F_MASK(cursor, WT_CURSTD_KEY_SET) == WT_CURSTD_KEY_INT);
+ WT_ASSERT(session, F_MASK(cursor, WT_CURSTD_VALUE_SET) == 0);
err: CURSOR_UPDATE_API_END(session, ret);
return (ret);
diff --git a/src/cursor/cur_index.c b/src/cursor/cur_index.c
index 0ab992bc88c..6fc01c0421f 100644
--- a/src/cursor/cur_index.c
+++ b/src/cursor/cur_index.c
@@ -240,7 +240,17 @@ __curindex_search(WT_CURSOR *cursor)
found_key = child->key;
if (found_key.size < cursor->key.size)
WT_ERR(WT_NOTFOUND);
- found_key.size = cursor->key.size;
+
+ /*
+ * Custom collators expect to see complete keys, pass an item containing
+ * all the visible fields so it unpacks correctly.
+ */
+ if (cindex->index->collator != NULL &&
+ !F_ISSET(cursor, WT_CURSTD_RAW_SEARCH))
+ WT_ERR(__wt_struct_repack(session, child->key_format,
+ cindex->iface.key_format, &child->key, &found_key));
+ else
+ found_key.size = cursor->key.size;
WT_ERR(__wt_compare(
session, cindex->index->collator, &cursor->key, &found_key, &cmp));
@@ -307,8 +317,18 @@ __curindex_search_near(WT_CURSOR *cursor, int *exact)
* 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;
+ if (found_key.size > cursor->key.size) {
+ /*
+ * Custom collators expect to see complete keys, pass an item
+ * containing all the visible fields so it unpacks correctly.
+ */
+ if (cindex->index->collator != NULL)
+ WT_ERR(__wt_struct_repack(session,
+ cindex->child->key_format, cindex->iface.key_format,
+ &child->key, &found_key));
+ else
+ found_key.size = cursor->key.size;
+ }
WT_ERR(__wt_compare(
session, cindex->index->collator, &cursor->key, &found_key, exact));
@@ -520,8 +540,8 @@ __wt_curindex_open(WT_SESSION_IMPL *session,
WT_ERR(__curindex_open_colgroups(session, cindex, cfg));
if (F_ISSET(cursor, WT_CURSTD_DUMP_JSON))
- __wt_json_column_init(
- cursor, table->key_format, &idx->colconf, &table->colconf);
+ __wt_json_column_init(cursor, uri, table->key_format,
+ &idx->colconf, &table->colconf);
if (0) {
err: WT_TRET(__curindex_close(cursor));
diff --git a/src/cursor/cur_join.c b/src/cursor/cur_join.c
index 013a64ef2d5..80afaf798dc 100644
--- a/src/cursor/cur_join.c
+++ b/src/cursor/cur_join.c
@@ -185,7 +185,7 @@ __curjoin_iter_set_entry(WT_CURSOR_JOIN_ITER *iter, u_int entry_pos)
size = strlen(to_dup->internal_uri) + 3;
WT_ERR(__wt_calloc(session, size, 1, &uri));
- snprintf(uri, size, "%s()", to_dup->internal_uri);
+ WT_ERR(__wt_snprintf(uri, size, "%s()", to_dup->internal_uri));
if ((c = iter->cursor) == NULL || !WT_STREQ(c->uri, uri)) {
iter->cursor = NULL;
if (c != NULL)
@@ -270,7 +270,7 @@ again:
iter->positioned = true;
return (ret);
}
- else if (ret == WT_NOTFOUND) {
+ if (ret == WT_NOTFOUND) {
WT_RET(__curjoin_iter_close_all(iter->child));
entry->subjoin->iter = NULL;
iter->child = NULL;
@@ -518,8 +518,7 @@ __curjoin_entry_in_range(WT_SESSION_IMPL *session, WT_CURSOR_JOIN_ENTRY *entry,
}
if (disjunction && end == endmax)
return (WT_NOTFOUND);
- else
- return (0);
+ return (0);
}
typedef struct {
@@ -930,7 +929,7 @@ __curjoin_init_next(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin,
if ((proj = cjoin->projection) != NULL) {
size = strlen(urimain) + strlen(proj) + 1;
WT_ERR(__wt_calloc(session, size, 1, &mainbuf));
- snprintf(mainbuf, size, "%s%s", urimain, proj);
+ WT_ERR(__wt_snprintf(mainbuf, size, "%s%s", urimain, proj));
urimain = mainbuf;
}
WT_ERR(__wt_open_cursor(session, urimain, (WT_CURSOR *)cjoin, config,
@@ -975,8 +974,8 @@ __curjoin_init_next(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin,
if (!iterable && F_ISSET(je, WT_CURJOIN_ENTRY_BLOOM)) {
if (session->txn.isolation == WT_ISO_READ_UNCOMMITTED)
WT_ERR_MSG(session, EINVAL,
- "join cursors with Bloom filters cannot be "
- "used with read-uncommitted isolation");
+ "join cursors with Bloom filters cannot be "
+ "used with read-uncommitted isolation");
if (je->bloom == NULL) {
/*
* Look for compatible filters to be shared,
@@ -1149,8 +1148,8 @@ __curjoin_open_main(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin,
newsize = strlen(cjoin->table->name) + idx->colconf.len + 1;
WT_ERR(__wt_calloc(session, 1, newsize, &main_uri));
- snprintf(main_uri, newsize, "%s%.*s",
- cjoin->table->name, (int)idx->colconf.len, idx->colconf.str);
+ WT_ERR(__wt_snprintf(main_uri, newsize, "%s%.*s",
+ cjoin->table->name, (int)idx->colconf.len, idx->colconf.str));
WT_ERR(__wt_open_cursor(session, main_uri,
(WT_CURSOR *)cjoin, raw_cfg, &entry->main));
if (idx->extractor == NULL) {
@@ -1163,7 +1162,8 @@ __curjoin_open_main(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin,
*/
len = strlen(entry->main->value_format) + 3;
WT_ERR(__wt_calloc(session, len, 1, &newformat));
- snprintf(newformat, len, "%s0x", entry->main->value_format);
+ WT_ERR(__wt_snprintf(
+ newformat, len, "%s0x", entry->main->value_format));
__wt_free(session, entry->main->value_format);
entry->main->value_format = newformat;
}
@@ -1532,8 +1532,8 @@ __wt_curjoin_join(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin,
len = strlen(cindex->iface.key_format) + 3;
WT_RET(__wt_calloc(session, len, 1,
&entry->repack_format));
- snprintf(entry->repack_format, len, "%s0x",
- cindex->iface.key_format);
+ WT_RET(__wt_snprintf(entry->repack_format,
+ len, "%s0x", cindex->iface.key_format));
}
}
return (0);
diff --git a/src/cursor/cur_json.c b/src/cursor/cur_json.c
index a0a3ffdd974..e8ddb767863 100644
--- a/src/cursor/cur_json.c
+++ b/src/cursor/cur_json.c
@@ -8,8 +8,8 @@
#include "wt_internal.h"
-static size_t __json_unpack_put(WT_SESSION_IMPL *, void *, u_char *, size_t,
- WT_CONFIG_ITEM *);
+static int __json_unpack_put(
+ WT_SESSION_IMPL *, void *, u_char *, size_t, WT_CONFIG_ITEM *, size_t *);
static inline int __json_struct_size(WT_SESSION_IMPL *, const void *, size_t,
const char *, WT_CONFIG_ITEM *, bool, size_t *);
static inline int __json_struct_unpackv(WT_SESSION_IMPL *, const void *, size_t,
@@ -23,20 +23,20 @@ static int __json_pack_size(WT_SESSION_IMPL *, const char *, WT_CONFIG_ITEM *,
bool, const char *, size_t *);
#define WT_PACK_JSON_GET(session, pv, jstr) do { \
- switch (pv.type) { \
+ switch ((pv).type) { \
case 'x': \
break; \
case 's': \
case 'S': \
- WT_RET(json_string_arg(session, &jstr, &pv.u.item)); \
- pv.type = pv.type == 's' ? 'j' : 'J'; \
+ WT_RET(json_string_arg(session, &(jstr), &(pv).u.item));\
+ (pv).type = (pv).type == 's' ? 'j' : 'J'; \
break; \
case 'b': \
case 'h': \
case 'i': \
case 'l': \
case 'q': \
- WT_RET(json_int_arg(session, &jstr, &pv.u.i)); \
+ WT_RET(json_int_arg(session, &(jstr), &(pv).u.i)); \
break; \
case 'B': \
case 'H': \
@@ -46,11 +46,11 @@ static int __json_pack_size(WT_SESSION_IMPL *, const char *, WT_CONFIG_ITEM *,
case 'r': \
case 'R': \
case 't': \
- WT_RET(json_uint_arg(session, &jstr, &pv.u.u)); \
+ WT_RET(json_uint_arg(session, &(jstr), &(pv).u.u)); \
break; \
case 'u': \
- WT_RET(json_string_arg(session, &jstr, &pv.u.item)); \
- pv.type = 'K'; \
+ WT_RET(json_string_arg(session, &(jstr), &(pv).u.item));\
+ (pv).type = 'K'; \
break; \
/* User format strings have already been validated. */ \
WT_ILLEGAL_VALUE(session); \
@@ -61,22 +61,22 @@ static int __json_pack_size(WT_SESSION_IMPL *, const char *, WT_CONFIG_ITEM *,
* __json_unpack_put --
* Calculate the size of a packed byte string as formatted for JSON.
*/
-static size_t
+static int
__json_unpack_put(WT_SESSION_IMPL *session, void *voidpv,
- u_char *buf, size_t bufsz, WT_CONFIG_ITEM *name)
+ u_char *buf, size_t bufsz, WT_CONFIG_ITEM *name, size_t *retsizep)
{
WT_PACK_VALUE *pv;
const u_char *p, *end;
size_t s, n;
pv = (WT_PACK_VALUE *)voidpv;
- s = (size_t)snprintf((char *)buf, bufsz, "\"%.*s\" : ",
- (int)name->len, name->str);
+
+ WT_RET(__wt_snprintf_len_set(
+ (char *)buf, bufsz, &s, "\"%.*s\" : ", (int)name->len, name->str));
if (s <= bufsz) {
bufsz -= s;
buf += s;
- }
- else
+ } else
bufsz = 0;
switch (pv->type) {
@@ -118,7 +118,8 @@ __json_unpack_put(WT_SESSION_IMPL *session, void *voidpv,
}
if (bufsz > 0)
*buf++ = '"';
- return (s);
+ *retsizep += s;
+ return (0);
case 'U':
case 'u':
s += 2;
@@ -140,14 +141,17 @@ __json_unpack_put(WT_SESSION_IMPL *session, void *voidpv,
}
if (bufsz > 0)
*buf++ = '"';
- return (s);
+ *retsizep += s;
+ return (0);
case 'b':
case 'h':
case 'i':
case 'l':
case 'q':
- return (s +
- (size_t)snprintf((char *)buf, bufsz, "%" PRId64, pv->u.i));
+ WT_RET(__wt_snprintf_len_incr(
+ (char *)buf, bufsz, &s, "%" PRId64, pv->u.i));
+ *retsizep += s;
+ return (0);
case 'B':
case 't':
case 'H':
@@ -156,11 +160,14 @@ __json_unpack_put(WT_SESSION_IMPL *session, void *voidpv,
case 'Q':
case 'r':
case 'R':
- return (s +
- (size_t)snprintf((char *)buf, bufsz, "%" PRId64, pv->u.u));
+ WT_RET(__wt_snprintf_len_incr(
+ (char *)buf, bufsz, &s, "%" PRId64, pv->u.u));
+ *retsizep += s;
+ return (0);
}
- __wt_err(session, EINVAL, "unknown pack-value type: %c", (int)pv->type);
- return ((size_t)-1);
+
+ WT_RET_MSG(session, EINVAL,
+ "unknown pack-value type: %c", (int)pv->type);
}
/*
@@ -194,7 +201,8 @@ __json_struct_size(WT_SESSION_IMPL *session, const void *buffer,
needcr = true;
WT_RET(__unpack_read(session, &pv, &p, (size_t)(end - p)));
WT_RET(__pack_name_next(&packname, &name));
- result += __json_unpack_put(session, &pv, NULL, 0, &name);
+ WT_RET(
+ __json_unpack_put(session, &pv, NULL, 0, &name, &result));
}
if (ret == WT_NOTFOUND)
ret = 0;
@@ -243,8 +251,9 @@ __json_struct_unpackv(WT_SESSION_IMPL *session,
needcr = true;
WT_RET(__unpack_read(session, &pv, &p, (size_t)(end - p)));
WT_RET(__pack_name_next(&packname, &name));
- jsize = __json_unpack_put(session,
- (u_char *)&pv, jbuf, jbufsize, &name);
+ jsize = 0;
+ WT_RET(__json_unpack_put(session,
+ (u_char *)&pv, jbuf, jbufsize, &name, &jsize));
WT_ASSERT(session, jsize <= jbufsize);
jbuf += jsize;
jbufsize -= jsize;
@@ -304,7 +313,6 @@ __wt_json_close(WT_SESSION_IMPL *session, WT_CURSOR *cursor)
__wt_free(session, json->value_buf);
__wt_free(session, json);
}
- return;
}
/*
@@ -323,33 +331,32 @@ __wt_json_unpack_char(u_char ch, u_char *buf, size_t bufsz, bool force_unicode)
if (bufsz >= 1)
*buf = ch;
return (1);
- } else {
- abbrev = '\0';
- switch (ch) {
- case '\\':
- case '"':
- abbrev = ch;
- break;
- case '\f':
- abbrev = 'f';
- break;
- case '\n':
- abbrev = 'n';
- break;
- case '\r':
- abbrev = 'r';
- break;
- case '\t':
- abbrev = 't';
- break;
- }
- if (abbrev != '\0') {
- if (bufsz >= 2) {
- *buf++ = '\\';
- *buf = abbrev;
- }
- return (2);
+ }
+ abbrev = '\0';
+ switch (ch) {
+ case '\\':
+ case '"':
+ abbrev = ch;
+ break;
+ case '\f':
+ abbrev = 'f';
+ break;
+ case '\n':
+ abbrev = 'n';
+ break;
+ case '\r':
+ abbrev = 'r';
+ break;
+ case '\t':
+ abbrev = 't';
+ break;
+ }
+ if (abbrev != '\0') {
+ if (bufsz >= 2) {
+ *buf++ = '\\';
+ *buf = abbrev;
}
+ return (2);
}
}
if (bufsz >= 6) {
@@ -369,11 +376,11 @@ __wt_json_unpack_char(u_char ch, u_char *buf, size_t bufsz, bool force_unicode)
* of column names.
*/
void
-__wt_json_column_init(WT_CURSOR *cursor, const char *keyformat,
+__wt_json_column_init(WT_CURSOR *cursor, const char *uri, const char *keyformat,
const WT_CONFIG_ITEM *idxconf, const WT_CONFIG_ITEM *colconf)
{
WT_CURSOR_JSON *json;
- const char *p, *end, *beginkey;
+ const char *beginkey, *end, *lparen, *p;
uint32_t keycnt, nkeys;
json = (WT_CURSOR_JSON *)cursor->json_private;
@@ -400,8 +407,16 @@ __wt_json_column_init(WT_CURSOR *cursor, const char *keyformat,
keycnt++;
p++;
}
- json->value_names.str = p;
- json->value_names.len = WT_PTRDIFF(end, p);
+ if ((lparen = strchr(uri, '(')) != NULL) {
+ /* This cursor is a projection. */
+ json->value_names.str = lparen;
+ json->value_names.len = strlen(lparen) - 1;
+ WT_ASSERT((WT_SESSION_IMPL *)cursor->session,
+ json->value_names.str[json->value_names.len] == ')');
+ } else {
+ json->value_names.str = p;
+ json->value_names.len = WT_PTRDIFF(end, p);
+ }
if (idxconf == NULL) {
if (p > beginkey)
p--;
@@ -413,16 +428,16 @@ __wt_json_column_init(WT_CURSOR *cursor, const char *keyformat,
#define MATCH_KEYWORD(session, in, result, keyword, matchval) do { \
size_t _kwlen = strlen(keyword); \
if (strncmp(in, keyword, _kwlen) == 0 && \
- !__wt_isalnum((u_char)in[_kwlen])) { \
- in += _kwlen; \
- result = matchval; \
+ !__wt_isalnum((u_char)(in)[_kwlen])) { \
+ (in) += _kwlen; \
+ (result) = matchval; \
} else { \
- const char *_bad = in; \
- while (__wt_isalnum((u_char)*in)) \
- in++; \
+ const char *_bad = (in); \
+ while (__wt_isalnum((u_char)*(in))) \
+ (in)++; \
WT_RET_MSG(session, EINVAL, \
"unknown keyword \"%.*s\" in JSON", \
- (int)(in - _bad), _bad); \
+ (int)((in) - _bad), _bad); \
} \
} while (0)
@@ -684,12 +699,13 @@ json_uint_arg(WT_SESSION_IMPL *session, const char **jstr, uint64_t *up)
#define JSON_EXPECT_TOKEN_GET(session, jstr, tokval, start, sz) do { \
int __tok; \
- WT_RET(__wt_json_token((WT_SESSION *)session, jstr, &__tok, &start, &sz));\
- if (__tok != tokval) \
+ WT_RET(__wt_json_token( \
+ (WT_SESSION *)(session), jstr, &__tok, &(start), &(sz))); \
+ if (__tok != (tokval)) \
WT_RET_MSG(session, EINVAL, \
"expected JSON %s, got %s", \
__wt_json_tokname(tokval), __wt_json_tokname(__tok)); \
- jstr = start + sz; \
+ (jstr) = (start) + (sz); \
} while (0)
#define JSON_EXPECT_TOKEN(session, jstr, tokval) do { \
diff --git a/src/cursor/cur_log.c b/src/cursor/cur_log.c
index 3ee6554b3c0..e5b56aa406f 100644
--- a/src/cursor/cur_log.c
+++ b/src/cursor/cur_log.c
@@ -305,7 +305,7 @@ __curlog_close(WT_CURSOR *cursor)
WT_ASSERT(session, FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED));
if (F_ISSET(cl, WT_CURLOG_ARCHIVE_LOCK))
- __wt_readunlock(session, conn->log->log_archive_lock);
+ __wt_readunlock(session, &conn->log->log_archive_lock);
__wt_free(session, cl->cur_lsn);
__wt_free(session, cl->next_lsn);
@@ -383,7 +383,7 @@ __wt_curlog_open(WT_SESSION_IMPL *session,
WT_ERR(__wt_log_force_write(session, 1, NULL));
/* Log cursors block archiving. */
- __wt_readlock(session, log->log_archive_lock);
+ __wt_readlock(session, &log->log_archive_lock);
F_SET(cl, WT_CURLOG_ARCHIVE_LOCK);
if (0) {
diff --git a/src/cursor/cur_metadata.c b/src/cursor/cur_metadata.c
index 10e2fdf28be..fbfc73956e2 100644
--- a/src/cursor/cur_metadata.c
+++ b/src/cursor/cur_metadata.c
@@ -16,7 +16,7 @@
WT_CURSOR_NEEDKEY(cursor); \
WT_ERR(__wt_buf_set(session, \
&((WT_CURSOR_METADATA *)(cursor))->file_cursor->key, \
- cursor->key.data, cursor->key.size)); \
+ (cursor)->key.data, (cursor)->key.size)); \
F_SET(((WT_CURSOR_METADATA *)(cursor))->file_cursor, \
WT_CURSTD_KEY_EXT); \
} while (0)
@@ -25,7 +25,7 @@
WT_CURSOR_NEEDVALUE(cursor); \
WT_ERR(__wt_buf_set(session, \
&((WT_CURSOR_METADATA *)(cursor))->file_cursor->value, \
- cursor->value.data, cursor->value.size)); \
+ (cursor)->value.data, (cursor)->value.size)); \
F_SET(((WT_CURSOR_METADATA *)(cursor))->file_cursor, \
WT_CURSTD_VALUE_EXT); \
} while (0)
diff --git a/src/cursor/cur_stat.c b/src/cursor/cur_stat.c
index 5fde64c74ca..0bff642370d 100644
--- a/src/cursor/cur_stat.c
+++ b/src/cursor/cur_stat.c
@@ -163,7 +163,6 @@ static void
__curstat_set_value(WT_CURSOR *cursor, ...)
{
WT_UNUSED(cursor);
- return;
}
/*
@@ -478,8 +477,8 @@ __curstat_join_desc(WT_CURSOR_STAT *cst, int slot, const char **resultp)
len = strlen("join: ") + strlen(sgrp->desc_prefix) +
strlen(static_desc) + 1;
WT_RET(__wt_realloc(session, NULL, len, &cst->desc_buf));
- snprintf(cst->desc_buf, len, "join: %s%s", sgrp->desc_prefix,
- static_desc);
+ WT_RET(__wt_snprintf(
+ cst->desc_buf, len, "join: %s%s", sgrp->desc_prefix, static_desc));
*resultp = cst->desc_buf;
return (0);
}
diff --git a/src/cursor/cur_std.c b/src/cursor/cur_std.c
index 6264de89df9..99a9e373354 100644
--- a/src/cursor/cur_std.c
+++ b/src/cursor/cur_std.c
@@ -144,6 +144,7 @@ __wt_cursor_set_notsup(WT_CURSOR *cursor)
*/
int
__wt_cursor_kv_not_set(WT_CURSOR *cursor, bool key)
+ WT_GCC_FUNC_ATTRIBUTE((cold))
{
WT_SESSION_IMPL *session;
@@ -632,6 +633,7 @@ __wt_cursor_reconfigure(WT_CURSOR *cursor, const char *config)
int
__wt_cursor_dup_position(WT_CURSOR *to_dup, WT_CURSOR *cursor)
{
+ WT_DECL_RET;
WT_ITEM key;
/*
@@ -661,9 +663,11 @@ __wt_cursor_dup_position(WT_CURSOR *to_dup, WT_CURSOR *cursor)
* cursors cannot reference application memory after cursor operations
* and that requirement will save the day.
*/
- WT_RET(cursor->search(cursor));
+ F_SET(cursor, WT_CURSTD_RAW_SEARCH);
+ ret = cursor->search(cursor);
+ F_CLR(cursor, WT_CURSTD_RAW_SEARCH);
- return (0);
+ return (ret);
}
/*
diff --git a/src/cursor/cur_table.c b/src/cursor/cur_table.c
index fae7667e44f..3b72bb0730f 100644
--- a/src/cursor/cur_table.c
+++ b/src/cursor/cur_table.c
@@ -14,8 +14,8 @@ 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); \
+ for (__i = 0, __cp = (ctable)->cg_cursors; \
+ __i < WT_COLGROUPS((ctable)->table); \
__i++, __cp++) \
WT_TRET((*__cp)->f(*__cp)); \
} while (0)
@@ -511,9 +511,16 @@ __curtable_insert(WT_CURSOR *cursor)
*/
F_SET(primary, flag_orig | WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT);
- if (ret == WT_DUPLICATE_KEY && F_ISSET(cursor, WT_CURSTD_OVERWRITE))
+ if (ret == WT_DUPLICATE_KEY && F_ISSET(cursor, WT_CURSTD_OVERWRITE)) {
WT_ERR(__curtable_update(cursor));
- else {
+
+ /*
+ * 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++) {
@@ -601,22 +608,53 @@ err: CURSOR_UPDATE_API_END(session, ret);
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);
+
+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);
@@ -769,7 +807,7 @@ __curtable_complete(WT_SESSION_IMPL *session, WT_TABLE *table)
return (0);
/* If the table is incomplete, wait on the table lock and recheck. */
- WT_WITH_TABLE_LOCK(session, complete = table->cg_complete);
+ 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",
@@ -951,7 +989,7 @@ __wt_curtable_open(WT_SESSION_IMPL *session,
if (F_ISSET(cursor, WT_CURSTD_DUMP_JSON))
__wt_json_column_init(
- cursor, table->key_format, NULL, &table->colconf);
+ cursor, uri, table->key_format, NULL, &table->colconf);
/*
* Open the colgroup cursors immediately: we're going to need them for
@@ -989,11 +1027,15 @@ __wt_curtable_open(WT_SESSION_IMPL *session,
if (0) {
err: if (*cursorp != NULL) {
- if (*cursorp != cursor)
- WT_TRET(__wt_cursor_close(*cursorp));
+ /*
+ * 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(__curtable_close(cursor));
+ WT_TRET(cursor->close(cursor));
}
__wt_scr_free(session, &tmp);