Description
Michael, if you specify an empty value column subset to an index, WT drops core.
Here's the test program, ripped out of examples/c/ex_schema.c:
#include <wiredtiger.h>
|
|
const char *home = "WT_TEST";
|
|
/*! [schema declaration] */
|
/* The C struct for the data we are storing in a WiredTiger table. */
|
typedef struct {
|
char country[5];
|
unsigned short year;
|
unsigned long long population;
|
} POP_RECORD;
|
|
POP_RECORD pop_data[] = {
|
{ "AU", 1900, 4000000 },
|
{ "AU", 2000, 19053186 },
|
{ "CAN", 1900, 5500000 },
|
{ "CAN", 2000, 31099561 },
|
{ "UK", 1900, 369000000 },
|
{ "UK", 2000, 59522468 },
|
{ "USA", 1900, 76212168 },
|
{ "USA", 2000, 301279593 },
|
{ "", 0, 0 }
|
};
|
/*! [schema declaration] */
|
|
int
|
main(void)
|
{
|
POP_RECORD *p;
|
WT_CONNECTION *conn;
|
WT_CURSOR *cursor;
|
WT_SESSION *session;
|
unsigned short year;
|
const char *country;
|
int ret;
|
|
system("rm -rf WT_TEST && mkdir WT_TEST");
|
ret = wiredtiger_open(home, NULL, "create", &conn);
|
ret = conn->open_session(conn, NULL, NULL, &session);
|
ret = session->create(session, "table:mytable",
|
"key_format=r,"
|
"value_format=5sHQ,"
|
"columns=(id,country,year,population)");
|
ret = session->create(session,
|
"index:mytable:country_plus_year", "columns=(country,year)");
|
ret = session->open_cursor(
|
session, "table:mytable", NULL, "append", &cursor);
|
for (p = pop_data; p->year != 0; p++) {
|
cursor->set_value(cursor, p->country, p->year, p->population);
|
ret = cursor->insert(cursor);
|
}
|
ret = cursor->close(cursor);
|
ret = session->open_cursor(session,
|
"index:mytable:country_plus_year()", NULL, NULL, &cursor);
|
while ((ret = cursor->next(cursor)) == 0) {
|
cursor->get_key(cursor, &country, &year);
|
printf("country %s, year %u\n", country, year);
|
}
|
|
ret = conn->close(conn, NULL);
|
return (ret);
|
}
|
The interesting line is:
ret = session->open_cursor(session,
|
"index:mytable:country_plus_year()", NULL, NULL, &cursor);
|
If you change it to:
ret = session->open_cursor(session,
|
"index:mytable:country_plus_year(year)", NULL, NULL, &cursor);
|
it works.
The stack is:
0x000000000044867c in __curindex_close (cursor=0x800c72b00)
|
at ../src/cursor/cur_index.c:281
|
281 if (*cp != NULL) {
|
(gdb) where
|
#0 0x000000000044867c in __curindex_close (cursor=0x800c72b00)
|
at ../src/cursor/cur_index.c:281
|
WT-1 0x0000000000448e43 in __wt_curindex_open (session=0x800c25430,
|
uri=0x47c0a0 "index:mytable:country_plus_year()", cfg=0x7fffffffe810,
|
cursorp=0x7fffffffe880) at ../src/cursor/cur_index.c:446
|
WT-2 0x0000000000414ecb in __wt_open_cursor (session=0x800c25430,
|
uri=0x47c0a0 "index:mytable:country_plus_year()", owner=0x0,
|
cfg=0x7fffffffe810, cursorp=0x7fffffffe880)
|
at ../src/session/session_api.c:201
|
WT-3 0x000000000041517c in __session_open_cursor (wt_session=0x800c25430,
|
uri=0x47c0a0 "index:mytable:country_plus_year()", to_dup=0x0, config=0x0,
|
cursorp=0x7fffffffe880) at ../src/session/session_api.c:243
|
WT-4 0x0000000000402102 in main ()
|
In summary, at around line 429 of cur_index.c, __wt_curindex_open() calls __wt_struct_reformat() with a "columns" value of "()", and it fails, returning not-found. That jumps to the err: label, which calls __curindex_close(), which has this loop:
for (i = 0, cp = cindex->cg_cursors;
|
i < WT_COLGROUPS(cindex->table); i++, cp++)
|
if (*cp != NULL) {
|
WT_TRET((*cp)->close(*cp));
|
*cp = NULL;
|
}
|
|
The table might have a non-zero number of column groups at this point, and even if it doesn't, WT_COLGROUPS returns a minimum value of 1.
In either case, cp == NULL and *cp drops core.
Sorry I'm dumping this to you, but I stared at it for a little while, and I wasn't sure what the right fix should be.