/* * __wt_schema_open_colgroups -- * Open the column groups for a table. */ int __wt_schema_open_colgroups(WT_SESSION_IMPL *session, WT_TABLE *table) { WT_COLGROUP *colgroup; WT_CONFIG cparser; WT_CONFIG_ITEM ckey, cval; WT_DECL_RET; WT_DECL_ITEM(buf); char *cgconfig; u_int i; WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_TABLE)); if (table->cg_complete) return (0); colgroup = NULL; cgconfig = NULL; WT_RET(__wt_scr_alloc(session, 0, &buf)); WT_ERR(__wt_config_subinit(session, &cparser, &table->cgconf)); /* Open each column group. */ for (i = 0; i < WT_COLGROUPS(table); i++) { if (table->ncolgroups > 0) WT_ERR(__wt_config_next(&cparser, &ckey, &cval)); else WT_CLEAR(ckey); /* * Always open from scratch: we may have failed part of the way * through opening a table, or column groups may have changed. */ __wt_schema_destroy_colgroup(session, &table->cgroups[i]); WT_ERR(__wt_buf_init(session, buf, 0)); WT_ERR(__wt_schema_colgroup_name(session, table, ckey.str, ckey.len, buf)); if ((ret = __wt_metadata_search( session, buf->data, &cgconfig)) != 0) { /* It is okay if the table is incomplete. */ if (ret == WT_NOTFOUND) ret = 0; goto err; } WT_ERR(__wt_calloc_one(session, &colgroup)); WT_ERR(__wt_strndup( session, buf->data, buf->size, &colgroup->name)); colgroup->config = cgconfig; cgconfig = NULL; WT_ERR(__wt_config_getones(session, colgroup->config, "columns", &colgroup->colconf)); WT_ERR(__wt_config_getones( session, colgroup->config, "source", &cval)); WT_ERR(__wt_strndup( session, cval.str, cval.len, &colgroup->source)); table->cgroups[i] = colgroup; colgroup = NULL; } if (!table->is_simple) { WT_ERR(__wt_table_check(session, table)); WT_ERR(__wt_buf_init(session, buf, 0)); WT_ERR(__wt_struct_plan(session, table, table->colconf.str, table->colconf.len, true, buf)); WT_ERR(__wt_strndup( session, buf->data, buf->size, &table->plan)); } table->cg_complete = true; err: __wt_scr_free(session, &buf); __wt_schema_destroy_colgroup(session, &colgroup); if (cgconfig != NULL) __wt_free(session, cgconfig); return (ret); }
/* * __wt_curindex_open -- * WT_SESSION->open_cursor method for index cursors. */ int __wt_curindex_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) { WT_CURSOR_STATIC_INIT(iface, __wt_cursor_get_key, /* get-key */ __curindex_get_value, /* get-value */ __wt_cursor_set_key, /* set-key */ __curindex_set_value, /* set-value */ __curindex_compare, /* compare */ __wt_cursor_equals, /* equals */ __curindex_next, /* next */ __curindex_prev, /* prev */ __curindex_reset, /* reset */ __curindex_search, /* search */ __curindex_search_near, /* search-near */ __wt_cursor_notsup, /* insert */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ __wt_cursor_reconfigure_notsup, /* reconfigure */ __curindex_close); /* close */ WT_CURSOR_INDEX *cindex; WT_CURSOR *cursor; WT_DECL_ITEM(tmp); WT_DECL_RET; WT_INDEX *idx; WT_TABLE *table; const char *columns, *idxname, *tablename; size_t namesize; tablename = uri; if (!WT_PREFIX_SKIP(tablename, "index:") || (idxname = strchr(tablename, ':')) == NULL) WT_RET_MSG(session, EINVAL, "Invalid cursor URI: '%s'", uri); namesize = (size_t)(idxname - tablename); ++idxname; if ((ret = __wt_schema_get_table(session, tablename, namesize, false, &table)) != 0) { if (ret == WT_NOTFOUND) WT_RET_MSG(session, EINVAL, "Cannot open cursor '%s' on unknown table", uri); return (ret); } columns = strchr(idxname, '('); if (columns == NULL) namesize = strlen(idxname); else namesize = (size_t)(columns - idxname); if ((ret = __wt_schema_open_index( session, table, idxname, namesize, &idx)) != 0) { __wt_schema_release_table(session, table); return (ret); } WT_RET(__wt_calloc_one(session, &cindex)); cursor = &cindex->iface; *cursor = iface; cursor->session = &session->iface; cindex->table = table; cindex->index = idx; cindex->key_plan = idx->key_plan; cindex->value_plan = idx->value_plan; cursor->internal_uri = idx->name; cursor->key_format = idx->idxkey_format; cursor->value_format = table->value_format; /* * XXX * A very odd corner case is an index with a recno key. * The only way to get here is by creating an index on a column store * using only the primary's recno as the index key. Disallow that for * now. */ if (WT_CURSOR_RECNO(cursor)) WT_ERR_MSG(session, WT_ERROR, "Column store indexes based on a record number primary " "key are not supported"); /* Handle projections. */ if (columns != NULL) { WT_ERR(__wt_scr_alloc(session, 0, &tmp)); 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, &cindex->value_plan)); } WT_ERR(__wt_cursor_init( cursor, cursor->internal_uri, owner, cfg, cursorp)); WT_ERR(__wt_open_cursor( session, idx->source, cursor, cfg, &cindex->child)); /* Open the column groups needed for this index cursor. */ 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); if (0) { err: WT_TRET(__curindex_close(cursor)); *cursorp = NULL; } __wt_scr_free(session, &tmp); return (ret); }
/* * __open_index -- * Open an index. */ static int __open_index(WT_SESSION_IMPL *session, WT_TABLE *table, WT_INDEX *idx) { WT_CONFIG colconf; WT_CONFIG_ITEM ckey, cval, metadata; WT_DECL_ITEM(buf); WT_DECL_ITEM(plan); WT_DECL_RET; u_int npublic_cols, i; WT_ERR(__wt_scr_alloc(session, 0, &buf)); /* Get the data source from the index config. */ WT_ERR(__wt_config_getones(session, idx->config, "source", &cval)); WT_ERR(__wt_strndup(session, cval.str, cval.len, &idx->source)); WT_ERR(__wt_config_getones(session, idx->config, "immutable", &cval)); if (cval.val) F_SET(idx, WT_INDEX_IMMUTABLE); /* * Compatibility: we didn't always maintain collator information in * index metadata, cope when it isn't found. */ WT_CLEAR(cval); WT_ERR_NOTFOUND_OK(__wt_config_getones( session, idx->config, "collator", &cval)); if (cval.len != 0) { WT_CLEAR(metadata); WT_ERR_NOTFOUND_OK(__wt_config_getones( session, idx->config, "app_metadata", &metadata)); WT_ERR(__wt_collator_config( session, idx->name, &cval, &metadata, &idx->collator, &idx->collator_owned)); } WT_ERR(__wt_extractor_config( session, idx->name, idx->config, &idx->extractor, &idx->extractor_owned)); WT_ERR(__wt_config_getones(session, idx->config, "key_format", &cval)); WT_ERR(__wt_strndup(session, cval.str, cval.len, &idx->key_format)); /* * The key format for an index is somewhat subtle: the application * specifies a set of columns that it will use for the key, but the * engine usually adds some hidden columns in order to derive the * primary key. These hidden columns are part of the file's key. * * The file's key_format is stored persistently, we need to calculate * the index cursor key format (which will usually omit some of those * keys). */ WT_ERR(__wt_buf_init(session, buf, 0)); WT_ERR(__wt_config_getones( session, idx->config, "columns", &idx->colconf)); /* Start with the declared index columns. */ WT_ERR(__wt_config_subinit(session, &colconf, &idx->colconf)); for (npublic_cols = 0; (ret = __wt_config_next(&colconf, &ckey, &cval)) == 0; ++npublic_cols) WT_ERR(__wt_buf_catfmt( session, buf, "%.*s,", (int)ckey.len, ckey.str)); if (ret != WT_NOTFOUND) goto err; /* * If we didn't find any columns, the index must have an extractor. * We don't rely on this unconditionally because it was only added to * the metadata after version 2.3.1. */ if (npublic_cols == 0) { WT_ERR(__wt_config_getones( session, idx->config, "index_key_columns", &cval)); npublic_cols = (u_int)cval.val; WT_ASSERT(session, npublic_cols != 0); for (i = 0; i < npublic_cols; i++) WT_ERR(__wt_buf_catfmt(session, buf, "\"bad col\",")); } /* * Now add any primary key columns from the table that are not * already part of the index key. */ WT_ERR(__wt_config_subinit(session, &colconf, &table->colconf)); for (i = 0; i < table->nkey_columns && (ret = __wt_config_next(&colconf, &ckey, &cval)) == 0; i++) { /* * If the primary key column is already in the secondary key, * don't add it again. */ if (__wt_config_subgetraw( session, &idx->colconf, &ckey, &cval) == 0) continue; WT_ERR(__wt_buf_catfmt( session, buf, "%.*s,", (int)ckey.len, ckey.str)); } WT_ERR_NOTFOUND_OK(ret); /* * If the table doesn't yet have its column groups, don't try to * calculate a plan: we are just checking that the index creation is * sane. */ if (!table->cg_complete) goto err; WT_ERR(__wt_scr_alloc(session, 0, &plan)); WT_ERR(__wt_struct_plan( session, table, buf->data, buf->size, false, plan)); WT_ERR(__wt_strndup(session, plan->data, plan->size, &idx->key_plan)); /* Set up the cursor key format (the visible columns). */ WT_ERR(__wt_buf_init(session, buf, 0)); WT_ERR(__wt_struct_truncate(session, idx->key_format, npublic_cols, buf)); WT_ERR(__wt_strndup( session, buf->data, buf->size, &idx->idxkey_format)); /* * Add a trailing padding byte to the format. This ensures that there * will be no special optimization of the last column, so the primary * key columns can be simply appended. */ WT_ERR(__wt_buf_catfmt(session, buf, "x")); WT_ERR(__wt_strndup(session, buf->data, buf->size, &idx->exkey_format)); /* By default, index cursor values are the table value columns. */ /* TODO Optimize to use index columns in preference to table lookups. */ WT_ERR(__wt_buf_init(session, plan, 0)); WT_ERR(__wt_struct_plan(session, table, table->colconf.str, table->colconf.len, true, plan)); WT_ERR(__wt_strndup(session, plan->data, plan->size, &idx->value_plan)); err: __wt_scr_free(session, &buf); __wt_scr_free(session, &plan); return (ret); }
/* * ___open_index -- * Open an index. */ static int __open_index(WT_SESSION_IMPL *session, WT_TABLE *table, WT_INDEX *idx) { WT_CONFIG colconf; WT_CONFIG_ITEM ckey, cval; WT_DECL_ITEM(buf); WT_DECL_ITEM(plan); WT_DECL_RET; u_int cursor_key_cols, i; WT_ERR(__wt_scr_alloc(session, 0, &buf)); /* Get the data source from the index config. */ WT_ERR(__wt_config_getones(session, idx->config, "source", &cval)); WT_ERR(__wt_buf_fmt( session, buf, "%.*s", (int)cval.len, cval.str)); idx->source = __wt_buf_steal(session, buf, NULL); idx->need_value = WT_PREFIX_MATCH(idx->source, "lsm:"); WT_ERR(__wt_config_getones(session, idx->config, "key_format", &cval)); WT_ERR(__wt_buf_fmt( session, buf, "%.*s", (int)cval.len, cval.str)); idx->key_format = __wt_buf_steal(session, buf, NULL); /* * The key format for an index is somewhat subtle: the application * specifies a set of columns that it will use for the key, but the * engine usually adds some hidden columns in order to derive the * primary key. These hidden columns are part of the file's key. * * The file's key_format is stored persistently, we need to calculate * the index cursor key format (which will usually omit some of those * keys). */ WT_ERR(__wt_config_getones( session, idx->config, "columns", &idx->colconf)); /* Start with the declared index columns. */ WT_ERR(__wt_config_subinit(session, &colconf, &idx->colconf)); cursor_key_cols = 0; while ((ret = __wt_config_next(&colconf, &ckey, &cval)) == 0) { WT_ERR(__wt_buf_catfmt( session, buf, "%.*s,", (int)ckey.len, ckey.str)); ++cursor_key_cols; } if (ret != 0 && ret != WT_NOTFOUND) goto err; /* * Now add any primary key columns from the table that are not * already part of the index key. */ WT_ERR(__wt_config_subinit(session, &colconf, &table->colconf)); for (i = 0; i < table->nkey_columns && (ret = __wt_config_next(&colconf, &ckey, &cval)) == 0; i++) { /* * If the primary key column is already in the secondary key, * don't add it again. */ if (__wt_config_subgetraw( session, &idx->colconf, &ckey, &cval) == 0) continue; WT_ERR(__wt_buf_catfmt( session, buf, "%.*s,", (int)ckey.len, ckey.str)); } if (ret != 0 && ret != WT_NOTFOUND) goto err; WT_ERR(__wt_scr_alloc(session, 0, &plan)); WT_ERR(__wt_struct_plan(session, table, buf->data, buf->size, 0, plan)); idx->key_plan = __wt_buf_steal(session, plan, NULL); /* Set up the cursor key format (the visible columns). */ WT_ERR(__wt_buf_init(session, buf, 0)); WT_ERR(__wt_struct_truncate(session, idx->key_format, cursor_key_cols, buf)); idx->idxkey_format = __wt_buf_steal(session, buf, NULL); /* By default, index cursor values are the table value columns. */ /* TODO Optimize to use index columns in preference to table lookups. */ WT_ERR(__wt_struct_plan(session, table, table->colconf.str, table->colconf.len, 1, plan)); idx->value_plan = __wt_buf_steal(session, plan, NULL); err: __wt_scr_free(&buf); __wt_scr_free(&plan); return (ret); }