summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cursor/cur_metadata.c158
-rw-r--r--src/include/cursor.h1
-rw-r--r--src/include/extern.h1
-rw-r--r--src/utilities/util_dump.c210
4 files changed, 155 insertions, 215 deletions
diff --git a/src/cursor/cur_metadata.c b/src/cursor/cur_metadata.c
index fc63ca13f7c..863c0c2b487 100644
--- a/src/cursor/cur_metadata.c
+++ b/src/cursor/cur_metadata.c
@@ -31,55 +31,87 @@
} while (0)
/*
- * __wt_schema_create_final --
- * Create a single configuration line from a set of configuration strings,
- * including all of the defaults declared for a session.create, and stripping
- * any configuration strings that don't belong in a session.create. Here for
- * the wt dump command utility, which reads a set of configuration strings and
- * needs to add in the defaults and then collapse them into single string for
- * a subsequent load.
+ * __schema_source_config --
+ * Extract the "source" configuration key, lookup its metadata.
*/
-int
-__wt_schema_create_final(
- WT_SESSION_IMPL *session, char *cfg_arg[], char **value_ret)
+static int
+__schema_source_config(WT_SESSION_IMPL *session, WT_CURSOR *srch,
+ char *config, char **result)
{
+ WT_CONFIG_ITEM cval;
+ WT_DECL_ITEM(buf);
WT_DECL_RET;
- u_int i;
- const char **cfg;
-
- /*
- * Count the entries in the original,
- * Allocate a copy with the defaults as the first entry,
- * Collapse the whole thing into a single configuration string (which
- * also strips any entries that don't appear in the first entry).
- */
- for (i = 0; cfg_arg[i] != NULL; ++i)
- ;
- WT_RET(__wt_calloc_def(session, i + 2, &cfg));
- cfg[0] = WT_CONFIG_BASE(session, WT_SESSION_create);
- for (i = 0; cfg_arg[i] != NULL; ++i)
- cfg[i + 1] = cfg_arg[i];
- cfg[i + 1] = NULL;
-
- ret = __wt_config_collapse(session, cfg, value_ret);
-
- __wt_free(session, cfg);
+ char *v;
+
+ WT_ERR(__wt_config_getones(session, config, "source", &cval));
+ WT_ERR(__wt_scr_alloc(session, cval.len + 10, &buf));
+ WT_ERR(__wt_buf_fmt(session, buf, "%.*s", (int)cval.len, cval.str));
+ srch->set_key(srch, buf->data);
+ if ((ret = srch->search(srch)) == WT_NOTFOUND)
+ WT_ERR(EINVAL);
+ WT_ERR(ret);
+ WT_ERR(srch->get_value(srch, &v));
+ WT_ERR(__wt_strdup(session, v, result));
+
+err: __wt_scr_free(session, &buf);
return (ret);
}
/*
- * __schema_create_strip --
- * Discard any configuration information from a schema entry that is not
- * applicable to an session.create call. Here for the metadata:create URI.
+ * __schema_create_collapse --
+ * Discard any configuration information from a schema entry that is
+ * not applicable to an session.create call.
+ *
+ * For a table URI that contains no named column groups, fold in the
+ * configuration from the implicit column group and its source. For a
+ * named column group URI, fold in its source.
*/
static int
-__schema_create_strip(
- WT_SESSION_IMPL *session, const char *value, char **value_ret)
+__schema_create_collapse(WT_SESSION_IMPL *session, WT_CURSOR_METADATA *mdc,
+ const char *key, char *value, char **value_ret)
{
- const char *cfg[] =
- { WT_CONFIG_BASE(session, WT_SESSION_create), value, NULL };
-
- return (__wt_config_collapse(session, cfg, value_ret));
+ WT_CURSOR *c;
+ WT_DECL_ITEM(buf);
+ WT_DECL_RET;
+ char *_cfg[5] = {NULL, NULL, NULL, value, NULL};
+ char **cfg, **firstcfg, **lastcfg, *v;
+
+ lastcfg = cfg = &_cfg[3]; /* position on value */
+ c = NULL;
+ if (key != NULL && WT_PREFIX_SKIP(key, "table:")) {
+ c = mdc->create_cursor;
+ WT_ERR(__wt_scr_alloc(session, 0, &buf));
+ /*
+ * When a table is created without column groups,
+ * we create one without a name.
+ */
+ WT_ERR(__wt_buf_fmt(session, buf, "colgroup:%s", key));
+ c->set_key(c, buf->data);
+ if ((ret = c->search(c)) == 0) {
+ WT_ERR(c->get_value(c, &v));
+ WT_ERR(__wt_strdup(session, v, --cfg));
+ WT_ERR(__schema_source_config(session, c, v, --cfg));
+ } else
+ WT_ERR_NOTFOUND_OK(ret);
+ } else if (key != NULL && WT_PREFIX_SKIP(key, "colgroup:")) {
+ if (strchr(key, ':') != NULL) {
+ c = mdc->create_cursor;
+ WT_ERR(__wt_strdup(session, value, --cfg));
+ WT_ERR(
+ __schema_source_config(session, c, value, --cfg));
+ }
+ }
+ firstcfg = cfg;
+ *--firstcfg = (char *)WT_CONFIG_BASE(session, WT_SESSION_create);
+ WT_ERR(__wt_config_collapse(
+ session, (const char **)firstcfg, value_ret));
+
+err: for (; cfg < lastcfg; cfg++)
+ __wt_free(session, *cfg);
+ if (c != NULL)
+ c->reset(c);
+ __wt_scr_free(session, &buf);
+ return (ret);
}
/*
@@ -95,17 +127,17 @@ __curmetadata_setkv(WT_CURSOR_METADATA *mdc, WT_CURSOR *fc)
WT_SESSION_IMPL *session;
char *value;
+ value = NULL;
c = &mdc->iface;
session = (WT_SESSION_IMPL *)c->session;
c->key.data = fc->key.data;
c->key.size = fc->key.size;
if (F_ISSET(mdc, WT_MDC_CREATEONLY)) {
- WT_RET(__schema_create_strip(session, fc->value.data, &value));
- ret = __wt_buf_set(
- session, &c->value, value, strlen(value) + 1);
- __wt_free(session, value);
- WT_RET(ret);
+ WT_ERR(__schema_create_collapse(session, mdc,
+ (char *)fc->key.data, (char *)fc->value.data, &value));
+ WT_ERR(__wt_buf_set(
+ session, &c->value, value, strlen(value) + 1));
} else {
c->value.data = fc->value.data;
c->value.size = fc->value.size;
@@ -115,7 +147,8 @@ __curmetadata_setkv(WT_CURSOR_METADATA *mdc, WT_CURSOR *fc)
F_CLR(mdc, WT_MDC_ONMETADATA);
F_SET(mdc, WT_MDC_POSITIONED);
- return (0);
+err: __wt_free(session, value);
+ return (ret);
}
/*
@@ -143,7 +176,8 @@ __curmetadata_metadata_search(WT_SESSION_IMPL *session, WT_CURSOR *cursor)
WT_RET(__wt_metadata_search(session, WT_METAFILE_URI, &value));
if (F_ISSET(mdc, WT_MDC_CREATEONLY)) {
- ret = __schema_create_strip(session, value, &stripped);
+ ret = __schema_create_collapse(session, mdc, NULL, value,
+ &stripped);
__wt_free(session, value);
WT_RET(ret);
value = stripped;
@@ -467,19 +501,20 @@ err: API_END_RET(session, ret);
static int
__curmetadata_close(WT_CURSOR *cursor)
{
- WT_CURSOR *file_cursor;
+ WT_CURSOR *c;
WT_CURSOR_METADATA *mdc;
WT_DECL_RET;
WT_SESSION_IMPL *session;
mdc = (WT_CURSOR_METADATA *)cursor;
- file_cursor = mdc->file_cursor;
- CURSOR_API_CALL(cursor, session,
- close, file_cursor == NULL ?
- NULL : ((WT_CURSOR_BTREE *)file_cursor)->btree);
-
- if (file_cursor != NULL)
- ret = file_cursor->close(file_cursor);
+ c = mdc->file_cursor;
+ CURSOR_API_CALL(cursor, session, close, c == NULL ?
+ NULL : ((WT_CURSOR_BTREE *)c)->btree);
+
+ if (c != NULL)
+ ret = c->close(c);
+ if ((c = mdc->create_cursor) != NULL)
+ WT_TRET(c->close(c));
WT_TRET(__wt_cursor_close(cursor));
err: API_END_RET(session, ret);
@@ -536,11 +571,18 @@ __wt_curmetadata_open(WT_SESSION_IMPL *session,
*/
WT_ERR(__wt_metadata_cursor_open(session, cfg[1], &mdc->file_cursor));
- WT_ERR(__wt_cursor_init(cursor, uri, owner, cfg, cursorp));
-
- /* If we are only returning create config, strip internal metadata. */
- if (WT_STREQ(uri, "metadata:create"))
+ /*
+ * If we are only returning create config, strip internal metadata.
+ * We'll need some extra cursors to pull out column group information
+ * and chase "source" entries.
+ */
+ if (WT_STREQ(uri, "metadata:create")) {
F_SET(mdc, WT_MDC_CREATEONLY);
+ WT_ERR(__wt_metadata_cursor_open(session, cfg[1],
+ &mdc->create_cursor));
+ }
+
+ WT_ERR(__wt_cursor_init(cursor, uri, owner, cfg, cursorp));
/*
* Metadata cursors default to readonly; if not set to not-readonly,
diff --git a/src/include/cursor.h b/src/include/cursor.h
index dce24f20844..f1fa4d193ac 100644
--- a/src/include/cursor.h
+++ b/src/include/cursor.h
@@ -425,6 +425,7 @@ struct __wt_cursor_metadata {
WT_CURSOR iface;
WT_CURSOR *file_cursor; /* Queries of regular metadata */
+ WT_CURSOR *create_cursor; /* Extra cursor for create option */
#define WT_MDC_CREATEONLY 0x01
#define WT_MDC_ONMETADATA 0x02
diff --git a/src/include/extern.h b/src/include/extern.h
index 5a12a7f333a..a18f2b3ef8c 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -297,7 +297,6 @@ extern int __wt_json_to_item(WT_SESSION_IMPL *session, const char *jstr, const c
extern ssize_t __wt_json_strlen(const char *src, size_t srclen);
extern int __wt_json_strncpy(WT_SESSION *wt_session, char **pdst, size_t dstlen, const char *src, size_t srclen) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_curlog_open(WT_SESSION_IMPL *session, const char *uri, const char *cfg[], WT_CURSOR **cursorp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
-extern int __wt_schema_create_final( WT_SESSION_IMPL *session, char *cfg_arg[], char **value_ret) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_curmetadata_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_curstat_dsrc_final(WT_CURSOR_STAT *cst);
extern int __wt_curstat_init(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *curjoin, const char *cfg[], WT_CURSOR_STAT *cst) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
diff --git a/src/utilities/util_dump.c b/src/utilities/util_dump.c
index 6344a90dddd..7dde13ee837 100644
--- a/src/utilities/util_dump.c
+++ b/src/utilities/util_dump.c
@@ -18,10 +18,10 @@ static int dump_prefix(WT_SESSION *, bool, bool);
static int dump_record(WT_CURSOR *, bool, bool);
static int dump_suffix(WT_SESSION *, bool);
static int dump_table_config(WT_SESSION *, WT_CURSOR *, const char *, bool);
-static int dump_table_config_complex(
- WT_SESSION *, WT_CURSOR *, WT_CURSOR *, const char *, const char *, bool);
+static int dump_table_parts_config(
+ WT_SESSION *, WT_CURSOR *, const char *, const char *, bool);
static int dup_json_string(const char *, char **);
-static int print_config(WT_SESSION *, const char *, char *[], bool, bool);
+static int print_config(WT_SESSION *, const char *, const char *, bool, bool);
static int usage(void);
int
@@ -146,9 +146,9 @@ dump_config(WT_SESSION *session, const char *uri, bool hex, bool json)
/* Open a metadata cursor. */
if ((ret = session->open_cursor(
- session, "metadata:", NULL, NULL, &cursor)) != 0) {
+ session, "metadata:create", NULL, NULL, &cursor)) != 0) {
fprintf(stderr, "%s: %s: session.open_cursor: %s\n", progname,
- "metadata:", session->strerror(session, ret));
+ "metadata:create", session->strerror(session, ret));
return (1);
}
/*
@@ -202,7 +202,7 @@ dump_json_end(WT_SESSION *session)
/*
* dump_json_begin --
- * Output the dump file header prefix.
+ * Output a separator between two JSON outputs in a list.
*/
static int
dump_json_separator(WT_SESSION *session)
@@ -232,18 +232,8 @@ static int
dump_table_config(
WT_SESSION *session, WT_CURSOR *cursor, const char *uri, bool json)
{
- WT_CONFIG_ITEM cval;
- WT_CURSOR *srch;
WT_DECL_RET;
- size_t len;
- int tret;
- bool complex_table;
const char *name, *v;
- char *p, **cfg, *_cfg[4] = {NULL, NULL, NULL, NULL};
-
- p = NULL;
- srch = NULL;
- cfg = &_cfg[3];
/* Get the table name. */
if ((name = strchr(uri, ':')) == NULL) {
@@ -258,105 +248,39 @@ dump_table_config(
*/
cursor->set_key(cursor, uri);
if ((ret = cursor->search(cursor)) != 0)
- WT_ERR(util_cerr(cursor, "search", ret));
+ return (util_cerr(cursor, "search", ret));
if ((ret = cursor->get_value(cursor, &v)) != 0)
- WT_ERR(util_cerr(cursor, "get_value", ret));
- if ((*--cfg = strdup(v)) == NULL)
- WT_ERR(util_err(session, errno, NULL));
-
- /*
- * Workaround for WiredTiger "simple" table handling. Simple tables
- * have column-group entries, but they aren't listed in the metadata's
- * table entry, and the name is different from other column-groups.
- * Figure out if it's a simple table and in that case, retrieve the
- * column-group's configuration value and the column-group's "source"
- * entry, where the column-group entry overrides the source's.
- */
- complex_table = false;
- if (WT_PREFIX_MATCH(uri, "table:")) {
- len = strlen("colgroup:") + strlen(name) + 1;
- if ((p = malloc(len)) == NULL)
- WT_ERR(util_err(session, errno, NULL));
- (void)snprintf(p, len, "colgroup:%s", name);
- cursor->set_key(cursor, p);
- if ((ret = cursor->search(cursor)) == 0) {
- if ((ret = cursor->get_value(cursor, &v)) != 0)
- WT_ERR(util_cerr(cursor, "get_value", ret));
- if ((*--cfg = strdup(v)) == NULL)
- WT_ERR(util_err(session, errno, NULL));
- if ((ret =__wt_config_getones(
- (WT_SESSION_IMPL *)session,
- *cfg, "source", &cval)) != 0)
- WT_ERR(util_err(
- session, ret, "%s: source entry", p));
- free(p);
- len = cval.len + 10;
- if ((p = malloc(len)) == NULL)
- WT_ERR(util_err(session, errno, NULL));
- (void)snprintf(p, len, "%.*s", (int)cval.len, cval.str);
- cursor->set_key(cursor, p);
- if ((ret = cursor->search(cursor)) != 0)
- WT_ERR(util_cerr(cursor, "search", ret));
- if ((ret = cursor->get_value(cursor, &v)) != 0)
- WT_ERR(util_cerr(cursor, "get_value", ret));
- if ((*--cfg = strdup(v)) == NULL)
- WT_ERR(util_err(session, errno, NULL));
- } else
- complex_table = true;
- }
-
- WT_ERR(print_config(session, uri, cfg, json, true));
+ return (util_cerr(cursor, "get_value", ret));
- /*
- * The underlying table configuration function needs a second
- * cursor: open one before calling it, it makes error handling
- * hugely simpler.
- */
- if ((ret = session->open_cursor(
- session, "metadata:", NULL, NULL, &srch)) != 0)
- WT_ERR(util_cerr(cursor, "open_cursor", ret));
-
- if (complex_table)
- WT_ERR(dump_table_config_complex(
- session, cursor, srch, name, "colgroup:", json));
- else if (json && printf(
- " \"colgroups\" : [],\n") < 0)
- WT_ERR(util_cerr(cursor, NULL, EIO));
+ WT_RET(print_config(session, uri, v, json, true));
- WT_ERR(dump_table_config_complex(
- session, cursor, srch, name, "index:", json));
+ WT_RET(dump_table_parts_config(
+ session, cursor, name, "colgroup:", json));
+ WT_RET(dump_table_parts_config(
+ session, cursor, name, "index:", json));
-err: if (srch != NULL && (tret = srch->close(srch)) != 0) {
- tret = util_cerr(cursor, "close", tret);
- if (ret == 0)
- ret = tret;
- }
- free(p);
- free(_cfg[0]);
- free(_cfg[1]);
- free(_cfg[2]);
- return (ret);
+ return (0);
}
/*
- * dump_table_config_complex --
- * Dump the column groups or indices for a table.
+ * dump_table_parts_config --
+ * Dump the column groups or indices parts with a table.
*/
static int
-dump_table_config_complex(WT_SESSION *session, WT_CURSOR *cursor,
- WT_CURSOR *srch, const char *name, const char *entry, bool json)
+dump_table_parts_config(WT_SESSION *session, WT_CURSOR *cursor,
+ const char *name, const char *entry, bool json)
{
- WT_CONFIG_ITEM cval;
WT_DECL_RET;
bool multiple;
const char *groupname, *key, *sep;
size_t len;
int exact;
const char *v;
- char *p, *cfg[3] = {NULL, NULL, NULL};
+ char *uriprefix;
multiple = false;
sep = "";
+ uriprefix = NULL;
if (json) {
if (strcmp(entry, "colgroup:") == 0) {
@@ -368,82 +292,61 @@ dump_table_config_complex(WT_SESSION *session, WT_CURSOR *cursor,
if (printf(" \"%s\" : [", groupname) < 0)
return (util_err(session, EIO, NULL));
}
+
+ len = strlen(entry) + strlen(name) + 1;
+ if ((uriprefix = malloc(len)) == NULL)
+ return util_err(session, errno, NULL);
+
+ snprintf(uriprefix, len, "%s%s", entry, name);
+
/*
* Search the file looking for column group and index key/value pairs:
* for each one, look up the related source information and append it
* to the base record, where the column group and index configuration
* overrides the source configuration.
*/
- cursor->set_key(cursor, entry);
- if ((ret = cursor->search_near(cursor, &exact)) != 0) {
- if (ret == WT_NOTFOUND)
- return (0);
+ cursor->set_key(cursor, uriprefix);
+ ret = cursor->search_near(cursor, &exact);
+ free(uriprefix);
+ if (ret == WT_NOTFOUND)
+ return (0);
+ if (ret != 0)
return (util_cerr(cursor, "search_near", ret));
- }
- if (exact >= 0)
+
+ /*
+ * An exact match is only possible for column groups, and indicates
+ * there is an implicit (unnamed) column group. Any configuration
+ * for such a column group has already been folded into the
+ * configuration for the associated table, so it is not interesting.
+ */
+ if (exact > 0)
goto match;
- while ((ret = cursor->next(cursor)) == 0) {
+ while (exact != 0 && (ret = cursor->next(cursor)) == 0) {
match: if ((ret = cursor->get_key(cursor, &key)) != 0)
return (util_cerr(cursor, "get_key", ret));
/* Check if we've finished the list of entries. */
- if (!WT_PREFIX_MATCH(key, entry))
+ if (!WT_PREFIX_MATCH(key, entry) ||
+ !WT_PREFIX_MATCH(key + strlen(entry), name))
break;
- /*
- * Check for a table name match. This test will match "simple"
- * table column-groups as well as the more complex ones, but
- * the previous version of the test was wrong and we're only
- * in this function in the case of complex tables.
- */
- if (!WT_PREFIX_MATCH(key + strlen(entry), name))
- continue;
-
- /* Get the value. */
if ((ret = cursor->get_value(cursor, &v)) != 0)
return (util_cerr(cursor, "get_value", ret));
- if ((cfg[1] = strdup(v)) == NULL)
- return (util_err(session, errno, NULL));
-
- /* Crack it and get the underlying source. */
- if ((ret = __wt_config_getones(
- (WT_SESSION_IMPL *)session, cfg[1], "source", &cval)) != 0)
- return (
- util_err(session, ret, "%s: source entry", key));
-
- /* Nul-terminate the source entry. */
- len = cval.len + 10;
- if ((p = malloc(len)) == NULL)
- return (util_err(session, errno, NULL));
- (void)snprintf(p, len, "%.*s", (int)cval.len, cval.str);
- srch->set_key(srch, p);
- if ((ret = srch->search(srch)) != 0)
- ret = util_err(session, ret, "%s: %s", key, p);
- free(p);
- if (ret != 0)
- return (1);
-
- /* Get the source's value. */
- if ((ret = srch->get_value(srch, &v)) != 0)
- return (util_cerr(cursor, "get_value", ret));
- if ((cfg[0] = strdup(v)) == NULL)
- return (util_err(session, errno, NULL));
- if (json && printf("%s\n", multiple ? "," : "") < 0)
+ if (json && printf("%s\n", (multiple ? "," : "")) < 0)
return (util_err(session, EIO, NULL));
/*
* The dumped configuration string is the original key plus the
* source's configuration, where the values of the original key
* override any source configurations of the same name.
*/
- if (print_config(session, key, cfg, json, false) != 0)
+ if (print_config(session, key, v, json, false) != 0)
return (util_err(session, EIO, NULL));
multiple = true;
}
- if (json && printf("\n ]%s\n", sep) < 0)
+ if (json && printf("%s]%s\n",
+ (multiple ? "\n " : ""), sep) < 0)
return (util_err(session, EIO, NULL));
- free(cfg[0]);
- free(cfg[1]);
if (ret == 0 || ret == WT_NOTFOUND)
return (0);
@@ -573,11 +476,11 @@ dup_json_string(const char *str, char **result)
* Output a key/value URI pair by combining v1 and v2.
*/
static int
-print_config(
- WT_SESSION *session, const char *key, char *cfg[], bool json, bool toplevel)
+print_config(WT_SESSION *session, const char *key, const char *cfg, bool json,
+ bool toplevel)
{
WT_DECL_RET;
- char *jsonconfig, *value_ret;
+ char *jsonconfig;
/*
* We have all of the object configuration, but don't have the default
@@ -585,13 +488,9 @@ print_config(
* defaults and collapse it all into one load configuration string.
*/
jsonconfig = NULL;
- if ((ret = __wt_schema_create_final(
- (WT_SESSION_IMPL *)session, cfg, &value_ret)) != 0)
- return (util_err(session, ret, NULL));
- if (json && (ret = dup_json_string(value_ret, &jsonconfig)) != 0) {
- free(value_ret);
+ if (json && (ret = dup_json_string(cfg, &jsonconfig)) != 0)
return (util_err(session, ret, NULL));
- }
+
if (json) {
if (toplevel)
ret = printf(
@@ -604,8 +503,7 @@ print_config(
" \"config\" : \"%s\"\n"
" }", key, jsonconfig);
} else
- ret = printf("%s\n%s\n", key, value_ret);
- free(value_ret);
+ ret = printf("%s\n%s\n", key, cfg);
free(jsonconfig);
if (ret < 0)
return (util_err(session, EIO, NULL));