summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/src/schema/schema_plan.c
diff options
context:
space:
mode:
authorLuke Chen <luke.chen@mongodb.com>2019-09-05 15:55:04 +1000
committerLuke Chen <luke.chen@mongodb.com>2019-09-05 15:55:04 +1000
commitd2c2e6c73c424d5a28d5bd2a9031e4796a5e4371 (patch)
tree457f5fe506097b766e5e1695ba9d7d2662910416 /src/third_party/wiredtiger/src/schema/schema_plan.c
parent41a74df493503fec4ce054cc380a0d7eb01d374c (diff)
downloadmongo-d2c2e6c73c424d5a28d5bd2a9031e4796a5e4371.tar.gz
Import wiredtiger: 543111d3d8737ada1b741b3a25a201feb2ed13a3 from branch mongodb-4.0
ref: 48bf8dae7c..543111d3d8 for: 4.0.13 WT-4502 Assertion checking hazard pointers on page discard is too strong WT-4658 Apply Clang Format WT-4792 Add stat to track pages queued for eviction after LRU sorting WT-4840 WT_CURSOR.modify must require explicit, snapshot-isolation transaction WT-4869 Stop adding cache pressure when eviction is falling behind WT-4881 Soften the restrictions on re-entering reconciliation WT-4882 Improve checkpoint performance when there are large metadata pages WT-4892 Improve statistics about forced eviction WT-4893 Fix a race between internal page child-page eviction checks and cursors in the tree WT-4895 Fix debug eviction mode so it chooses skew more randomly WT-4898 Don't allow the eviction server to reconcile if it's busy WT-4920 Add statistics tracking when eviction server is waiting for page transitions WT-4957 Revert part of a change about when pages are queued for urgent eviction WT-5050 Assertion failure during urgent eviction of metadata page
Diffstat (limited to 'src/third_party/wiredtiger/src/schema/schema_plan.c')
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_plan.c673
1 files changed, 323 insertions, 350 deletions
diff --git a/src/third_party/wiredtiger/src/schema/schema_plan.c b/src/third_party/wiredtiger/src/schema/schema_plan.c
index f7efa49b0a3..67b6567632c 100644
--- a/src/third_party/wiredtiger/src/schema/schema_plan.c
+++ b/src/third_party/wiredtiger/src/schema/schema_plan.c
@@ -10,400 +10,373 @@
/*
* __find_next_col --
- * Find the next column to use for a plan.
+ * Find the next column to use for a plan.
*/
static int
-__find_next_col(WT_SESSION_IMPL *session, WT_TABLE *table,
- WT_CONFIG_ITEM *colname, u_int *cgnump, u_int *colnump, char *coltype)
+__find_next_col(WT_SESSION_IMPL *session, WT_TABLE *table, WT_CONFIG_ITEM *colname, u_int *cgnump,
+ u_int *colnump, char *coltype)
{
- WT_COLGROUP *colgroup;
- WT_CONFIG conf;
- WT_CONFIG_ITEM cval, k, v;
- WT_DECL_RET;
- u_int cg, col, foundcg, foundcol, matchcg, matchcol;
- bool getnext;
-
- foundcg = foundcol = UINT_MAX;
- matchcg = *cgnump;
- matchcol = (*coltype == WT_PROJ_KEY) ?
- *colnump : *colnump + table->nkey_columns;
-
- getnext = true;
- for (colgroup = NULL, cg = 0; cg < WT_COLGROUPS(table); cg++) {
- colgroup = table->cgroups[cg];
-
- /*
- * If there is only one column group, we just scan through all
- * of the columns. For tables with multiple column groups, we
- * look at the key columns once, then go through the value
- * columns for each group.
- */
- if (cg == 0) {
- cval = table->colconf;
- col = 0;
- } else {
-cgcols: cval = colgroup->colconf;
- col = table->nkey_columns;
- }
- __wt_config_subinit(session, &conf, &cval);
- for (; (ret = __wt_config_next(&conf, &k, &v)) == 0; col++) {
- if (k.len == colname->len &&
- strncmp(colname->str, k.str, k.len) == 0) {
- if (getnext) {
- foundcg = cg;
- foundcol = col;
- }
- getnext = cg == matchcg && col == matchcol;
- }
- if (cg == 0 && table->ncolgroups > 0 &&
- col == table->nkey_columns - 1)
- goto cgcols;
- }
- WT_RET_TEST(ret != WT_NOTFOUND, ret);
-
- colgroup = NULL;
- }
-
- if (foundcg == UINT_MAX)
- return (WT_NOTFOUND);
-
- *cgnump = foundcg;
- if (foundcol < table->nkey_columns) {
- *coltype = WT_PROJ_KEY;
- *colnump = foundcol;
- } else {
- *coltype = WT_PROJ_VALUE;
- *colnump = foundcol - table->nkey_columns;
- }
- return (0);
+ WT_COLGROUP *colgroup;
+ WT_CONFIG conf;
+ WT_CONFIG_ITEM cval, k, v;
+ WT_DECL_RET;
+ u_int cg, col, foundcg, foundcol, matchcg, matchcol;
+ bool getnext;
+
+ foundcg = foundcol = UINT_MAX;
+ matchcg = *cgnump;
+ matchcol = (*coltype == WT_PROJ_KEY) ? *colnump : *colnump + table->nkey_columns;
+
+ getnext = true;
+ for (colgroup = NULL, cg = 0; cg < WT_COLGROUPS(table); cg++) {
+ colgroup = table->cgroups[cg];
+
+ /*
+ * If there is only one column group, we just scan through all of the columns. For tables
+ * with multiple column groups, we look at the key columns once, then go through the value
+ * columns for each group.
+ */
+ if (cg == 0) {
+ cval = table->colconf;
+ col = 0;
+ } else {
+cgcols:
+ cval = colgroup->colconf;
+ col = table->nkey_columns;
+ }
+ __wt_config_subinit(session, &conf, &cval);
+ for (; (ret = __wt_config_next(&conf, &k, &v)) == 0; col++) {
+ if (k.len == colname->len && strncmp(colname->str, k.str, k.len) == 0) {
+ if (getnext) {
+ foundcg = cg;
+ foundcol = col;
+ }
+ getnext = cg == matchcg && col == matchcol;
+ }
+ if (cg == 0 && table->ncolgroups > 0 && col == table->nkey_columns - 1)
+ goto cgcols;
+ }
+ WT_RET_TEST(ret != WT_NOTFOUND, ret);
+
+ colgroup = NULL;
+ }
+
+ if (foundcg == UINT_MAX)
+ return (WT_NOTFOUND);
+
+ *cgnump = foundcg;
+ if (foundcol < table->nkey_columns) {
+ *coltype = WT_PROJ_KEY;
+ *colnump = foundcol;
+ } else {
+ *coltype = WT_PROJ_VALUE;
+ *colnump = foundcol - table->nkey_columns;
+ }
+ return (0);
}
/*
* __wt_schema_colcheck --
- * Check that a list of columns matches a (key,value) format pair.
+ * Check that a list of columns matches a (key,value) format pair.
*/
int
-__wt_schema_colcheck(WT_SESSION_IMPL *session,
- const char *key_format, const char *value_format, WT_CONFIG_ITEM *colconf,
- u_int *kcolsp, u_int *vcolsp)
+__wt_schema_colcheck(WT_SESSION_IMPL *session, const char *key_format, const char *value_format,
+ WT_CONFIG_ITEM *colconf, u_int *kcolsp, u_int *vcolsp)
{
- WT_CONFIG conf;
- WT_CONFIG_ITEM k, v;
- WT_DECL_PACK_VALUE(pv);
- WT_DECL_RET;
- WT_PACK pack;
- u_int kcols, ncols, vcols;
-
- WT_RET(__pack_init(session, &pack, key_format));
- for (kcols = 0; (ret = __pack_next(&pack, &pv)) == 0; kcols++)
- ;
- WT_RET_NOTFOUND_OK(ret);
-
- WT_RET(__pack_init(session, &pack, value_format));
- for (vcols = 0; (ret = __pack_next(&pack, &pv)) == 0; vcols++)
- ;
- WT_RET_TEST(ret != WT_NOTFOUND, ret);
-
- /* Walk through the named columns. */
- __wt_config_subinit(session, &conf, colconf);
- for (ncols = 0; (ret = __wt_config_next(&conf, &k, &v)) == 0; ncols++)
- ;
- WT_RET_TEST(ret != WT_NOTFOUND, ret);
-
- if (ncols != 0 && ncols != kcols + vcols)
- WT_RET_MSG(session, EINVAL, "Number of columns in '%.*s' "
- "does not match key format '%s' plus value format '%s'",
- (int)colconf->len, colconf->str, key_format, value_format);
-
- if (kcolsp != NULL)
- *kcolsp = kcols;
- if (vcolsp != NULL)
- *vcolsp = vcols;
-
- return (0);
+ WT_CONFIG conf;
+ WT_CONFIG_ITEM k, v;
+ WT_DECL_PACK_VALUE(pv);
+ WT_DECL_RET;
+ WT_PACK pack;
+ u_int kcols, ncols, vcols;
+
+ WT_RET(__pack_init(session, &pack, key_format));
+ for (kcols = 0; (ret = __pack_next(&pack, &pv)) == 0; kcols++)
+ ;
+ WT_RET_NOTFOUND_OK(ret);
+
+ WT_RET(__pack_init(session, &pack, value_format));
+ for (vcols = 0; (ret = __pack_next(&pack, &pv)) == 0; vcols++)
+ ;
+ WT_RET_TEST(ret != WT_NOTFOUND, ret);
+
+ /* Walk through the named columns. */
+ __wt_config_subinit(session, &conf, colconf);
+ for (ncols = 0; (ret = __wt_config_next(&conf, &k, &v)) == 0; ncols++)
+ ;
+ WT_RET_TEST(ret != WT_NOTFOUND, ret);
+
+ if (ncols != 0 && ncols != kcols + vcols)
+ WT_RET_MSG(session, EINVAL,
+ "Number of columns in '%.*s' "
+ "does not match key format '%s' plus value format '%s'",
+ (int)colconf->len, colconf->str, key_format, value_format);
+
+ if (kcolsp != NULL)
+ *kcolsp = kcols;
+ if (vcolsp != NULL)
+ *vcolsp = vcols;
+
+ return (0);
}
/*
* __wt_table_check --
- * Make sure all columns appear in a column group.
+ * Make sure all columns appear in a column group.
*/
int
__wt_table_check(WT_SESSION_IMPL *session, WT_TABLE *table)
{
- WT_CONFIG conf;
- WT_CONFIG_ITEM k, v;
- WT_DECL_RET;
- u_int cg, col, i;
- char coltype;
-
- if (table->is_simple)
- return (0);
-
- /* Walk through the columns. */
- __wt_config_subinit(session, &conf, &table->colconf);
-
- /* Skip over the key columns. */
- for (i = 0; i < table->nkey_columns; i++)
- WT_RET(__wt_config_next(&conf, &k, &v));
- cg = col = 0;
- coltype = 0;
- while ((ret = __wt_config_next(&conf, &k, &v)) == 0) {
- if (__find_next_col(
- session, table, &k, &cg, &col, &coltype) != 0)
- WT_RET_MSG(session, EINVAL,
- "Column '%.*s' in '%s' does not appear in a "
- "column group",
- (int)k.len, k.str, table->iface.name);
- /*
- * Column groups can't store key columns in their value:
- * __wt_struct_reformat should have already detected this case.
- */
- WT_ASSERT(session, coltype == WT_PROJ_VALUE);
-
- }
- WT_RET_TEST(ret != WT_NOTFOUND, ret);
-
- return (0);
+ WT_CONFIG conf;
+ WT_CONFIG_ITEM k, v;
+ WT_DECL_RET;
+ u_int cg, col, i;
+ char coltype;
+
+ if (table->is_simple)
+ return (0);
+
+ /* Walk through the columns. */
+ __wt_config_subinit(session, &conf, &table->colconf);
+
+ /* Skip over the key columns. */
+ for (i = 0; i < table->nkey_columns; i++)
+ WT_RET(__wt_config_next(&conf, &k, &v));
+ cg = col = 0;
+ coltype = 0;
+ while ((ret = __wt_config_next(&conf, &k, &v)) == 0) {
+ if (__find_next_col(session, table, &k, &cg, &col, &coltype) != 0)
+ WT_RET_MSG(session, EINVAL,
+ "Column '%.*s' in '%s' does not appear in a "
+ "column group",
+ (int)k.len, k.str, table->iface.name);
+ /*
+ * Column groups can't store key columns in their value:
+ * __wt_struct_reformat should have already detected this case.
+ */
+ WT_ASSERT(session, coltype == WT_PROJ_VALUE);
+ }
+ WT_RET_TEST(ret != WT_NOTFOUND, ret);
+
+ return (0);
}
/*
* __wt_struct_plan --
- * Given a table cursor containing a complete table, build the "projection
- * plan" to distribute the columns to dependent stores. A string
- * representing the plan will be appended to the plan buffer.
+ * Given a table cursor containing a complete table, build the "projection plan" to distribute
+ * the columns to dependent stores. A string representing the plan will be appended to the plan
+ * buffer.
*/
int
-__wt_struct_plan(WT_SESSION_IMPL *session, WT_TABLE *table,
- const char *columns, size_t len, bool value_only, WT_ITEM *plan)
+__wt_struct_plan(WT_SESSION_IMPL *session, WT_TABLE *table, const char *columns, size_t len,
+ bool value_only, WT_ITEM *plan)
{
- WT_CONFIG conf;
- WT_CONFIG_ITEM k, v;
- WT_DECL_RET;
- u_int cg, col, current_cg, current_col, i, start_cg, start_col;
- char coltype, current_coltype;
- bool have_it;
-
- start_cg = start_col = UINT_MAX; /* -Wuninitialized */
-
- /* Work through the value columns by skipping over the key columns. */
- __wt_config_initn(session, &conf, columns, len);
- if (value_only)
- for (i = 0; i < table->nkey_columns; i++)
- WT_RET(__wt_config_next(&conf, &k, &v));
-
- current_cg = cg = 0;
- current_col = col = INT_MAX;
- current_coltype = coltype = WT_PROJ_KEY; /* Keep lint quiet. */
- for (i = 0; (ret = __wt_config_next(&conf, &k, &v)) == 0; i++) {
- have_it = false;
-
- while ((ret = __find_next_col(session, table,
- &k, &cg, &col, &coltype)) == 0 &&
- (!have_it || cg != start_cg || col != start_col)) {
- /*
- * First we move to the column. If that is in a
- * different column group to the last column we
- * accessed, or before the last column in the same
- * column group, or moving from the key to the value,
- * we need to switch column groups or rewind.
- */
- if (current_cg != cg || current_col > col ||
- current_coltype != coltype) {
- WT_ASSERT(session, !value_only ||
- coltype == WT_PROJ_VALUE);
- WT_RET(__wt_buf_catfmt(
- session, plan, "%u%c", cg, coltype));
-
- /*
- * Set the current column group and column
- * within the table.
- */
- current_cg = cg;
- current_col = 0;
- current_coltype = coltype;
- }
- /* Now move to the column we want. */
- if (current_col < col) {
- if (col - current_col > 1)
- WT_RET(__wt_buf_catfmt(session,
- plan, "%u", col - current_col));
- WT_RET(__wt_buf_catfmt(session,
- plan, "%c", WT_PROJ_SKIP));
- }
- /*
- * Now copy the value in / out. In the common case,
- * where each value is used in one column, we do a
- * "next" operation. If the value is used again, we do
- * a "reuse" operation to avoid making another copy.
- */
- if (!have_it) {
- WT_RET(__wt_buf_catfmt(session,
- plan, "%c", WT_PROJ_NEXT));
-
- start_cg = cg;
- start_col = col;
- have_it = true;
- } else
- WT_RET(__wt_buf_catfmt(session,
- plan, "%c", WT_PROJ_REUSE));
- current_col = col + 1;
- }
- /*
- * We may fail to find a column if it is a custom extractor.
- * In that case, treat it as the first value column: we only
- * ever use such plans to extract the primary key from the
- * index.
- */
- if (ret == WT_NOTFOUND)
- WT_RET(__wt_buf_catfmt(session, plan,
- "0%c%c", WT_PROJ_VALUE, WT_PROJ_NEXT));
- }
- WT_RET_TEST(ret != WT_NOTFOUND, ret);
-
- /* Special case empty plans. */
- if (i == 0 && plan->size == 0)
- WT_RET(__wt_buf_set(session, plan, "", 1));
-
- return (0);
+ WT_CONFIG conf;
+ WT_CONFIG_ITEM k, v;
+ WT_DECL_RET;
+ u_int cg, col, current_cg, current_col, i, start_cg, start_col;
+ char coltype, current_coltype;
+ bool have_it;
+
+ start_cg = start_col = UINT_MAX; /* -Wuninitialized */
+
+ /* Work through the value columns by skipping over the key columns. */
+ __wt_config_initn(session, &conf, columns, len);
+ if (value_only)
+ for (i = 0; i < table->nkey_columns; i++)
+ WT_RET(__wt_config_next(&conf, &k, &v));
+
+ current_cg = cg = 0;
+ current_col = col = INT_MAX;
+ current_coltype = coltype = WT_PROJ_KEY; /* Keep lint quiet. */
+ for (i = 0; (ret = __wt_config_next(&conf, &k, &v)) == 0; i++) {
+ have_it = false;
+
+ while ((ret = __find_next_col(session, table, &k, &cg, &col, &coltype)) == 0 &&
+ (!have_it || cg != start_cg || col != start_col)) {
+ /*
+ * First we move to the column. If that is in a different column group to the last
+ * column we accessed, or before the last column in the same column group, or moving
+ * from the key to the value, we need to switch column groups or rewind.
+ */
+ if (current_cg != cg || current_col > col || current_coltype != coltype) {
+ WT_ASSERT(session, !value_only || coltype == WT_PROJ_VALUE);
+ WT_RET(__wt_buf_catfmt(session, plan, "%u%c", cg, coltype));
+
+ /*
+ * Set the current column group and column within the table.
+ */
+ current_cg = cg;
+ current_col = 0;
+ current_coltype = coltype;
+ }
+ /* Now move to the column we want. */
+ if (current_col < col) {
+ if (col - current_col > 1)
+ WT_RET(__wt_buf_catfmt(session, plan, "%u", col - current_col));
+ WT_RET(__wt_buf_catfmt(session, plan, "%c", WT_PROJ_SKIP));
+ }
+ /*
+ * Now copy the value in / out. In the common case,
+ * where each value is used in one column, we do a
+ * "next" operation. If the value is used again, we do
+ * a "reuse" operation to avoid making another copy.
+ */
+ if (!have_it) {
+ WT_RET(__wt_buf_catfmt(session, plan, "%c", WT_PROJ_NEXT));
+
+ start_cg = cg;
+ start_col = col;
+ have_it = true;
+ } else
+ WT_RET(__wt_buf_catfmt(session, plan, "%c", WT_PROJ_REUSE));
+ current_col = col + 1;
+ }
+ /*
+ * We may fail to find a column if it is a custom extractor. In that case, treat it as the
+ * first value column: we only ever use such plans to extract the primary key from the
+ * index.
+ */
+ if (ret == WT_NOTFOUND)
+ WT_RET(__wt_buf_catfmt(session, plan, "0%c%c", WT_PROJ_VALUE, WT_PROJ_NEXT));
+ }
+ WT_RET_TEST(ret != WT_NOTFOUND, ret);
+
+ /* Special case empty plans. */
+ if (i == 0 && plan->size == 0)
+ WT_RET(__wt_buf_set(session, plan, "", 1));
+
+ return (0);
}
/*
* __find_column_format --
- * Find the format of the named column.
+ * Find the format of the named column.
*/
static int
-__find_column_format(WT_SESSION_IMPL *session, WT_TABLE *table,
- WT_CONFIG_ITEM *colname, bool value_only, WT_PACK_VALUE *pv)
+__find_column_format(WT_SESSION_IMPL *session, WT_TABLE *table, WT_CONFIG_ITEM *colname,
+ bool value_only, WT_PACK_VALUE *pv)
{
- WT_CONFIG conf;
- WT_CONFIG_ITEM k, v;
- WT_DECL_RET;
- WT_PACK pack;
- bool inkey;
-
- __wt_config_subinit(session, &conf, &table->colconf);
- WT_RET(__pack_init(session, &pack, table->key_format));
- inkey = true;
-
- while ((ret = __wt_config_next(&conf, &k, &v)) == 0) {
- if ((ret = __pack_next(&pack, pv)) == WT_NOTFOUND && inkey) {
- ret = __pack_init(session, &pack, table->value_format);
- if (ret == 0)
- ret = __pack_next(&pack, pv);
- inkey = false;
- }
- if (ret != 0)
- return (ret);
-
- if (k.len == colname->len &&
- strncmp(colname->str, k.str, k.len) == 0) {
- if (value_only && inkey)
- return (__wt_set_return(session, EINVAL));
- return (0);
- }
- }
-
- return (ret);
+ WT_CONFIG conf;
+ WT_CONFIG_ITEM k, v;
+ WT_DECL_RET;
+ WT_PACK pack;
+ bool inkey;
+
+ __wt_config_subinit(session, &conf, &table->colconf);
+ WT_RET(__pack_init(session, &pack, table->key_format));
+ inkey = true;
+
+ while ((ret = __wt_config_next(&conf, &k, &v)) == 0) {
+ if ((ret = __pack_next(&pack, pv)) == WT_NOTFOUND && inkey) {
+ ret = __pack_init(session, &pack, table->value_format);
+ if (ret == 0)
+ ret = __pack_next(&pack, pv);
+ inkey = false;
+ }
+ if (ret != 0)
+ return (ret);
+
+ if (k.len == colname->len && strncmp(colname->str, k.str, k.len) == 0) {
+ if (value_only && inkey)
+ return (__wt_set_return(session, EINVAL));
+ return (0);
+ }
+ }
+
+ return (ret);
}
/*
* __wt_struct_reformat --
- * Given a table and a list of columns (which could be values in a column
- * group or index keys), calculate the resulting new format string.
- * The result will be appended to the format buffer.
+ * Given a table and a list of columns (which could be values in a column group or index keys),
+ * calculate the resulting new format string. The result will be appended to the format buffer.
*/
int
-__wt_struct_reformat(WT_SESSION_IMPL *session, WT_TABLE *table,
- const char *columns, size_t len, const char *extra_cols, bool value_only,
- WT_ITEM *format)
+__wt_struct_reformat(WT_SESSION_IMPL *session, WT_TABLE *table, const char *columns, size_t len,
+ const char *extra_cols, bool value_only, WT_ITEM *format)
{
- WT_CONFIG config;
- WT_CONFIG_ITEM k, next_k, next_v;
- WT_DECL_PACK_VALUE(pv);
- WT_DECL_RET;
- bool have_next;
-
- __wt_config_initn(session, &config, columns, len);
- /*
- * If an empty column list is specified, this will fail with
- * WT_NOTFOUND, that's okay.
- */
- WT_RET_NOTFOUND_OK(ret = __wt_config_next(&config, &next_k, &next_v));
- if (ret == WT_NOTFOUND) {
- if (extra_cols != NULL) {
- __wt_config_init(session, &config, extra_cols);
- WT_RET(__wt_config_next(&config, &next_k, &next_v));
- extra_cols = NULL;
- } else if (format->size == 0) {
- WT_RET(__wt_buf_set(session, format, "", 1));
- return (0);
- }
- }
- do {
- k = next_k;
- ret = __wt_config_next(&config, &next_k, &next_v);
- if (ret != 0 && ret != WT_NOTFOUND)
- return (ret);
- have_next = ret == 0;
-
- if (!have_next && extra_cols != NULL) {
- __wt_config_init(session, &config, extra_cols);
- WT_RET(__wt_config_next(&config, &next_k, &next_v));
- have_next = true;
- extra_cols = NULL;
- }
-
- if ((ret = __find_column_format(session,
- table, &k, value_only, &pv)) != 0) {
- if (value_only && ret == EINVAL)
- WT_RET_MSG(session, EINVAL,
- "A column group cannot store key column "
- "'%.*s' in its value", (int)k.len, k.str);
- WT_RET_MSG(session, EINVAL,
- "Column '%.*s' not found", (int)k.len, k.str);
- }
-
- /*
- * Check whether we're moving an unsized WT_ITEM from the end
- * to the middle, or vice-versa. This determines whether the
- * size needs to be prepended. This is the only case where the
- * destination size can be larger than the source size.
- */
- if (pv.type == 'u' && !pv.havesize && have_next)
- pv.type = 'U';
- else if (pv.type == 'U' && !have_next)
- pv.type = 'u';
-
- if (pv.havesize)
- WT_RET(__wt_buf_catfmt(session,
- format, "%" PRIu32 "%c", pv.size, pv.type));
- else
- WT_RET(__wt_buf_catfmt(session, format, "%c", pv.type));
- } while (have_next);
-
- return (0);
+ WT_CONFIG config;
+ WT_CONFIG_ITEM k, next_k, next_v;
+ WT_DECL_PACK_VALUE(pv);
+ WT_DECL_RET;
+ bool have_next;
+
+ __wt_config_initn(session, &config, columns, len);
+ /*
+ * If an empty column list is specified, this will fail with WT_NOTFOUND, that's okay.
+ */
+ WT_RET_NOTFOUND_OK(ret = __wt_config_next(&config, &next_k, &next_v));
+ if (ret == WT_NOTFOUND) {
+ if (extra_cols != NULL) {
+ __wt_config_init(session, &config, extra_cols);
+ WT_RET(__wt_config_next(&config, &next_k, &next_v));
+ extra_cols = NULL;
+ } else if (format->size == 0) {
+ WT_RET(__wt_buf_set(session, format, "", 1));
+ return (0);
+ }
+ }
+ do {
+ k = next_k;
+ ret = __wt_config_next(&config, &next_k, &next_v);
+ if (ret != 0 && ret != WT_NOTFOUND)
+ return (ret);
+ have_next = ret == 0;
+
+ if (!have_next && extra_cols != NULL) {
+ __wt_config_init(session, &config, extra_cols);
+ WT_RET(__wt_config_next(&config, &next_k, &next_v));
+ have_next = true;
+ extra_cols = NULL;
+ }
+
+ if ((ret = __find_column_format(session, table, &k, value_only, &pv)) != 0) {
+ if (value_only && ret == EINVAL)
+ WT_RET_MSG(session, EINVAL,
+ "A column group cannot store key column "
+ "'%.*s' in its value",
+ (int)k.len, k.str);
+ WT_RET_MSG(session, EINVAL, "Column '%.*s' not found", (int)k.len, k.str);
+ }
+
+ /*
+ * Check whether we're moving an unsized WT_ITEM from the end to the middle, or vice-versa.
+ * This determines whether the size needs to be prepended. This is the only case where the
+ * destination size can be larger than the source size.
+ */
+ if (pv.type == 'u' && !pv.havesize && have_next)
+ pv.type = 'U';
+ else if (pv.type == 'U' && !have_next)
+ pv.type = 'u';
+
+ if (pv.havesize)
+ WT_RET(__wt_buf_catfmt(session, format, "%" PRIu32 "%c", pv.size, pv.type));
+ else
+ WT_RET(__wt_buf_catfmt(session, format, "%c", pv.type));
+ } while (have_next);
+
+ return (0);
}
/*
* __wt_struct_truncate --
- * Return a packing string for the first N columns in a value.
+ * Return a packing string for the first N columns in a value.
*/
int
-__wt_struct_truncate(WT_SESSION_IMPL *session,
- const char *input_fmt, u_int ncols, WT_ITEM *format)
+__wt_struct_truncate(WT_SESSION_IMPL *session, const char *input_fmt, u_int ncols, WT_ITEM *format)
{
- WT_DECL_PACK_VALUE(pv);
- WT_PACK pack;
-
- WT_RET(__pack_init(session, &pack, input_fmt));
- while (ncols-- > 0) {
- WT_RET(__pack_next(&pack, &pv));
- if (pv.havesize)
- WT_RET(__wt_buf_catfmt(session,
- format, "%" PRIu32 "%c", pv.size, pv.type));
- else
- WT_RET(__wt_buf_catfmt(session, format, "%c", pv.type));
- }
-
- return (0);
+ WT_DECL_PACK_VALUE(pv);
+ WT_PACK pack;
+
+ WT_RET(__pack_init(session, &pack, input_fmt));
+ while (ncols-- > 0) {
+ WT_RET(__pack_next(&pack, &pv));
+ if (pv.havesize)
+ WT_RET(__wt_buf_catfmt(session, format, "%" PRIu32 "%c", pv.size, pv.type));
+ else
+ WT_RET(__wt_buf_catfmt(session, format, "%c", pv.type));
+ }
+
+ return (0);
}