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.