1 /*-
2 * Copyright (c) 2014-2018 MongoDB, Inc.
3 * Copyright (c) 2008-2014 WiredTiger, Inc.
4 * All rights reserved.
5 *
6 * See the file LICENSE for redistribution information.
7 */
8
9 #include "wt_internal.h"
10
11 /*
12 * Custom NEED macros for metadata cursors - that copy the values into the
13 * backing metadata table cursor.
14 */
15 #define WT_MD_CURSOR_NEEDKEY(cursor) do { \
16 WT_ERR(__cursor_needkey(cursor)); \
17 WT_ERR(__wt_buf_set(session, \
18 &((WT_CURSOR_METADATA *)(cursor))->file_cursor->key, \
19 (cursor)->key.data, (cursor)->key.size)); \
20 F_SET(((WT_CURSOR_METADATA *)(cursor))->file_cursor, \
21 WT_CURSTD_KEY_EXT); \
22 } while (0)
23
24 #define WT_MD_CURSOR_NEEDVALUE(cursor) do { \
25 WT_ERR(__cursor_needvalue(cursor)); \
26 WT_ERR(__wt_buf_set(session, \
27 &((WT_CURSOR_METADATA *)(cursor))->file_cursor->value, \
28 (cursor)->value.data, (cursor)->value.size)); \
29 F_SET(((WT_CURSOR_METADATA *)(cursor))->file_cursor, \
30 WT_CURSTD_VALUE_EXT); \
31 } while (0)
32
33 /*
34 * __schema_source_config --
35 * Extract the "source" configuration key, lookup its metadata.
36 */
37 static int
__schema_source_config(WT_SESSION_IMPL * session,WT_CURSOR * srch,const char * config,const char ** result)38 __schema_source_config(WT_SESSION_IMPL *session,
39 WT_CURSOR *srch, const char *config, const char **result)
40 {
41 WT_CONFIG_ITEM cval;
42 WT_DECL_ITEM(buf);
43 WT_DECL_RET;
44 char *v;
45
46 WT_ERR(__wt_config_getones(session, config, "source", &cval));
47 WT_ERR(__wt_scr_alloc(session, cval.len + 10, &buf));
48 WT_ERR(__wt_buf_fmt(session, buf, "%.*s", (int)cval.len, cval.str));
49 srch->set_key(srch, buf->data);
50 if ((ret = srch->search(srch)) != 0)
51 WT_ERR_MSG(session, ret,
52 "metadata information for source configuration"
53 " \"%s\" not found",
54 (const char *)buf->data);
55 WT_ERR(srch->get_value(srch, &v));
56 WT_ERR(__wt_strdup(session, v, result));
57
58 err: __wt_scr_free(session, &buf);
59 return (ret);
60 }
61
62 /*
63 * __schema_create_collapse --
64 * Discard any configuration information from a schema entry that is
65 * not applicable to an session.create call.
66 *
67 * For a table URI that contains no named column groups, fold in the
68 * configuration from the implicit column group and its source. For a
69 * named column group URI, fold in its source.
70 */
71 static int
__schema_create_collapse(WT_SESSION_IMPL * session,WT_CURSOR_METADATA * mdc,const char * key,const char * value,char ** value_ret)72 __schema_create_collapse(WT_SESSION_IMPL *session, WT_CURSOR_METADATA *mdc,
73 const char *key, const char *value, char **value_ret)
74 {
75 WT_CONFIG cparser;
76 WT_CONFIG_ITEM cgconf, ckey, cval;
77 WT_CURSOR *c;
78 WT_DECL_ITEM(buf);
79 WT_DECL_RET;
80 const char *_cfg[5] = {NULL, NULL, NULL, value, NULL};
81 const char **cfg, **firstcfg, **lastcfg, *v;
82
83 lastcfg = cfg = &_cfg[3]; /* position on value */
84 c = NULL;
85 if (key != NULL && WT_PREFIX_SKIP(key, "table:")) {
86 /*
87 * Check if the table has declared column groups. If it does,
88 * don't attempt to open the automatically created column
89 * group for simple tables.
90 */
91 WT_RET(__wt_config_getones(
92 session, value, "colgroups", &cgconf));
93
94 __wt_config_subinit(session, &cparser, &cgconf);
95 if ((ret = __wt_config_next(&cparser, &ckey, &cval)) == 0)
96 goto skip;
97 WT_RET_NOTFOUND_OK(ret);
98
99 c = mdc->create_cursor;
100 WT_ERR(__wt_scr_alloc(session, 0, &buf));
101 /*
102 * When a table is created without column groups,
103 * we create one without a name.
104 */
105 WT_ERR(__wt_buf_fmt(session, buf, "colgroup:%s", key));
106 c->set_key(c, buf->data);
107 if ((ret = c->search(c)) != 0)
108 WT_ERR_MSG(session, ret,
109 "metadata information for source configuration"
110 " \"%s\" not found",
111 (const char *)buf->data);
112 WT_ERR(c->get_value(c, &v));
113 WT_ERR(__wt_strdup(session, v, --cfg));
114 WT_ERR(__schema_source_config(session, c, v, --cfg));
115 } else if (key != NULL && WT_PREFIX_SKIP(key, "colgroup:")) {
116 if (strchr(key, ':') != NULL) {
117 c = mdc->create_cursor;
118 WT_ERR(__wt_strdup(session, value, --cfg));
119 WT_ERR(
120 __schema_source_config(session, c, value, --cfg));
121 }
122 }
123
124 skip: firstcfg = cfg;
125 *--firstcfg = WT_CONFIG_BASE(session, WT_SESSION_create);
126 WT_ERR(__wt_config_collapse(session, firstcfg, value_ret));
127
128 err: for (; cfg < lastcfg; cfg++)
129 __wt_free(session, *cfg);
130 if (c != NULL)
131 WT_TRET(c->reset(c));
132 __wt_scr_free(session, &buf);
133 return (ret);
134 }
135
136 /*
137 * __curmetadata_setkv --
138 * Copy key/value into the public cursor, stripping internal metadata for
139 * "create-only" cursors.
140 */
141 static int
__curmetadata_setkv(WT_CURSOR_METADATA * mdc,WT_CURSOR * fc)142 __curmetadata_setkv(WT_CURSOR_METADATA *mdc, WT_CURSOR *fc)
143 {
144 WT_CURSOR *c;
145 WT_DECL_RET;
146 WT_SESSION_IMPL *session;
147 char *value;
148
149 value = NULL;
150 c = &mdc->iface;
151 session = (WT_SESSION_IMPL *)c->session;
152
153 c->key.data = fc->key.data;
154 c->key.size = fc->key.size;
155 if (F_ISSET(mdc, WT_MDC_CREATEONLY)) {
156 WT_ERR(__schema_create_collapse(
157 session, mdc, fc->key.data, fc->value.data, &value));
158 WT_ERR(__wt_buf_set(
159 session, &c->value, value, strlen(value) + 1));
160 } else {
161 c->value.data = fc->value.data;
162 c->value.size = fc->value.size;
163 }
164
165 F_SET(c, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT);
166 F_CLR(mdc, WT_MDC_ONMETADATA);
167 F_SET(mdc, WT_MDC_POSITIONED);
168
169 err: __wt_free(session, value);
170 return (ret);
171 }
172
173 /*
174 * Check if a key matches the metadata. The public value is "metadata:",
175 * but also check for the internal version of the URI.
176 */
177 #define WT_KEY_IS_METADATA(key) \
178 ((key)->size > 0 && \
179 (WT_STRING_MATCH(WT_METADATA_URI, (key)->data, (key)->size - 1) ||\
180 WT_STRING_MATCH(WT_METAFILE_URI, (key)->data, (key)->size - 1)))
181
182 /*
183 * __curmetadata_metadata_search --
184 * Retrieve the metadata for the metadata table
185 */
186 static int
__curmetadata_metadata_search(WT_SESSION_IMPL * session,WT_CURSOR * cursor)187 __curmetadata_metadata_search(WT_SESSION_IMPL *session, WT_CURSOR *cursor)
188 {
189 WT_CURSOR_METADATA *mdc;
190 WT_DECL_RET;
191 char *value, *stripped;
192
193 mdc = (WT_CURSOR_METADATA *)cursor;
194
195 /* The metadata search interface allocates a new string in value. */
196 WT_RET(__wt_metadata_search(session, WT_METAFILE_URI, &value));
197
198 if (F_ISSET(mdc, WT_MDC_CREATEONLY)) {
199 ret = __schema_create_collapse(session, mdc, NULL, value,
200 &stripped);
201 __wt_free(session, value);
202 WT_RET(ret);
203 value = stripped;
204 }
205
206 ret = __wt_buf_setstr(session, &cursor->value, value);
207 __wt_free(session, value);
208 WT_RET(ret);
209
210 WT_RET(__wt_buf_setstr(session, &cursor->key, WT_METADATA_URI));
211
212 F_SET(mdc, WT_MDC_ONMETADATA | WT_MDC_POSITIONED);
213 F_SET(cursor, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT);
214 return (0);
215 }
216
217 /*
218 * __curmetadata_compare --
219 * WT_CURSOR->compare method for the metadata cursor type.
220 */
221 static int
__curmetadata_compare(WT_CURSOR * a,WT_CURSOR * b,int * cmpp)222 __curmetadata_compare(WT_CURSOR *a, WT_CURSOR *b, int *cmpp)
223 {
224 WT_CURSOR *a_file_cursor, *b_file_cursor;
225 WT_CURSOR_METADATA *a_mdc, *b_mdc;
226 WT_DECL_RET;
227 WT_SESSION_IMPL *session;
228
229 a_mdc = ((WT_CURSOR_METADATA *)a);
230 b_mdc = ((WT_CURSOR_METADATA *)b);
231 a_file_cursor = a_mdc->file_cursor;
232 b_file_cursor = b_mdc->file_cursor;
233
234 CURSOR_API_CALL(a, session,
235 compare, ((WT_CURSOR_BTREE *)a_file_cursor)->btree);
236
237 if (b->compare != __curmetadata_compare)
238 WT_ERR_MSG(session, EINVAL,
239 "Can only compare cursors of the same type");
240
241 WT_MD_CURSOR_NEEDKEY(a);
242 WT_MD_CURSOR_NEEDKEY(b);
243
244 if (F_ISSET(a_mdc, WT_MDC_ONMETADATA)) {
245 if (F_ISSET(b_mdc, WT_MDC_ONMETADATA))
246 *cmpp = 0;
247 else
248 *cmpp = 1;
249 } else if (F_ISSET(b_mdc, WT_MDC_ONMETADATA))
250 *cmpp = -1;
251 else
252 ret = a_file_cursor->compare(
253 a_file_cursor, b_file_cursor, cmpp);
254
255 err: API_END_RET(session, ret);
256 }
257
258 /*
259 * __curmetadata_next --
260 * WT_CURSOR->next method for the metadata cursor type.
261 */
262 static int
__curmetadata_next(WT_CURSOR * cursor)263 __curmetadata_next(WT_CURSOR *cursor)
264 {
265 WT_CURSOR *file_cursor;
266 WT_CURSOR_METADATA *mdc;
267 WT_DECL_RET;
268 WT_SESSION_IMPL *session;
269
270 mdc = (WT_CURSOR_METADATA *)cursor;
271 file_cursor = mdc->file_cursor;
272 CURSOR_API_CALL(cursor, session,
273 next, ((WT_CURSOR_BTREE *)file_cursor)->btree);
274
275 if (!F_ISSET(mdc, WT_MDC_POSITIONED))
276 WT_ERR(__curmetadata_metadata_search(session, cursor));
277 else {
278 /*
279 * When applications open metadata cursors, they expect to see
280 * all schema-level operations reflected in the results. Query
281 * at read-uncommitted to avoid confusion caused by the current
282 * transaction state.
283 *
284 * Don't exit from the scan if we find an incomplete entry:
285 * just skip over it.
286 */
287 for (;;) {
288 WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED,
289 ret = file_cursor->next(mdc->file_cursor));
290 WT_ERR(ret);
291 WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED,
292 ret = __curmetadata_setkv(mdc, file_cursor));
293 if (ret == 0)
294 break;
295 WT_ERR_NOTFOUND_OK(ret);
296 }
297 }
298
299 err: if (ret != 0) {
300 F_CLR(mdc, WT_MDC_POSITIONED | WT_MDC_ONMETADATA);
301 F_CLR(cursor, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT);
302 }
303 API_END_RET(session, ret);
304 }
305
306 /*
307 * __curmetadata_prev --
308 * WT_CURSOR->prev method for the metadata cursor type.
309 */
310 static int
__curmetadata_prev(WT_CURSOR * cursor)311 __curmetadata_prev(WT_CURSOR *cursor)
312 {
313 WT_CURSOR *file_cursor;
314 WT_CURSOR_METADATA *mdc;
315 WT_DECL_RET;
316 WT_SESSION_IMPL *session;
317
318 mdc = (WT_CURSOR_METADATA *)cursor;
319 file_cursor = mdc->file_cursor;
320 CURSOR_API_CALL(cursor, session,
321 prev, ((WT_CURSOR_BTREE *)file_cursor)->btree);
322
323 if (F_ISSET(mdc, WT_MDC_ONMETADATA)) {
324 ret = WT_NOTFOUND;
325 goto err;
326 }
327
328 /*
329 * Don't exit from the scan if we find an incomplete entry:
330 * just skip over it.
331 */
332 for (;;) {
333 WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED,
334 ret = file_cursor->prev(file_cursor));
335 if (ret == WT_NOTFOUND) {
336 WT_ERR(__curmetadata_metadata_search(session, cursor));
337 break;
338 }
339 WT_ERR(ret);
340 WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED,
341 ret = __curmetadata_setkv(mdc, file_cursor));
342 if (ret == 0)
343 break;
344 WT_ERR_NOTFOUND_OK(ret);
345 }
346
347 err: if (ret != 0) {
348 F_CLR(mdc, WT_MDC_POSITIONED | WT_MDC_ONMETADATA);
349 F_CLR(cursor, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT);
350 }
351 API_END_RET(session, ret);
352 }
353
354 /*
355 * __curmetadata_reset --
356 * WT_CURSOR->reset method for the metadata cursor type.
357 */
358 static int
__curmetadata_reset(WT_CURSOR * cursor)359 __curmetadata_reset(WT_CURSOR *cursor)
360 {
361 WT_CURSOR *file_cursor;
362 WT_CURSOR_METADATA *mdc;
363 WT_DECL_RET;
364 WT_SESSION_IMPL *session;
365
366 mdc = (WT_CURSOR_METADATA *)cursor;
367 file_cursor = mdc->file_cursor;
368 CURSOR_API_CALL_PREPARE_ALLOWED(cursor, session,
369 reset, ((WT_CURSOR_BTREE *)file_cursor)->btree);
370
371 if (F_ISSET(mdc, WT_MDC_POSITIONED) && !F_ISSET(mdc, WT_MDC_ONMETADATA))
372 ret = file_cursor->reset(file_cursor);
373 F_CLR(mdc, WT_MDC_POSITIONED | WT_MDC_ONMETADATA);
374 F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET);
375
376 err: API_END_RET(session, ret);
377 }
378
379 /*
380 * __curmetadata_search --
381 * WT_CURSOR->search method for the metadata cursor type.
382 */
383 static int
__curmetadata_search(WT_CURSOR * cursor)384 __curmetadata_search(WT_CURSOR *cursor)
385 {
386 WT_CURSOR *file_cursor;
387 WT_CURSOR_METADATA *mdc;
388 WT_DECL_RET;
389 WT_SESSION_IMPL *session;
390
391 mdc = (WT_CURSOR_METADATA *)cursor;
392 file_cursor = mdc->file_cursor;
393 CURSOR_API_CALL(cursor, session,
394 search, ((WT_CURSOR_BTREE *)file_cursor)->btree);
395
396 WT_MD_CURSOR_NEEDKEY(cursor);
397
398 if (WT_KEY_IS_METADATA(&cursor->key))
399 WT_ERR(__curmetadata_metadata_search(session, cursor));
400 else {
401 WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED,
402 ret = file_cursor->search(file_cursor));
403 WT_ERR(ret);
404 WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED,
405 ret = __curmetadata_setkv(mdc, file_cursor));
406 WT_ERR(ret);
407 }
408
409 err: if (ret != 0) {
410 F_CLR(mdc, WT_MDC_POSITIONED | WT_MDC_ONMETADATA);
411 F_CLR(cursor, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT);
412 }
413 API_END_RET(session, ret);
414 }
415
416 /*
417 * __curmetadata_search_near --
418 * WT_CURSOR->search_near method for the metadata cursor type.
419 */
420 static int
__curmetadata_search_near(WT_CURSOR * cursor,int * exact)421 __curmetadata_search_near(WT_CURSOR *cursor, int *exact)
422 {
423 WT_CURSOR *file_cursor;
424 WT_CURSOR_METADATA *mdc;
425 WT_DECL_RET;
426 WT_SESSION_IMPL *session;
427
428 mdc = (WT_CURSOR_METADATA *)cursor;
429 file_cursor = mdc->file_cursor;
430 CURSOR_API_CALL(cursor, session,
431 search_near, ((WT_CURSOR_BTREE *)file_cursor)->btree);
432
433 WT_MD_CURSOR_NEEDKEY(cursor);
434
435 if (WT_KEY_IS_METADATA(&cursor->key)) {
436 WT_ERR(__curmetadata_metadata_search(session, cursor));
437 *exact = 1;
438 } else {
439 WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED,
440 ret = file_cursor->search_near(file_cursor, exact));
441 WT_ERR(ret);
442 WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED,
443 ret = __curmetadata_setkv(mdc, file_cursor));
444 WT_ERR(ret);
445 }
446
447 err: if (ret != 0) {
448 F_CLR(mdc, WT_MDC_POSITIONED | WT_MDC_ONMETADATA);
449 F_CLR(cursor, WT_CURSTD_KEY_EXT | WT_CURSTD_VALUE_EXT);
450 }
451 API_END_RET(session, ret);
452 }
453
454 /*
455 * __curmetadata_insert --
456 * WT_CURSOR->insert method for the metadata cursor type.
457 */
458 static int
__curmetadata_insert(WT_CURSOR * cursor)459 __curmetadata_insert(WT_CURSOR *cursor)
460 {
461 WT_CURSOR *file_cursor;
462 WT_CURSOR_METADATA *mdc;
463 WT_DECL_RET;
464 WT_SESSION_IMPL *session;
465
466 mdc = (WT_CURSOR_METADATA *)cursor;
467 file_cursor = mdc->file_cursor;
468 CURSOR_API_CALL(cursor, session,
469 insert, ((WT_CURSOR_BTREE *)file_cursor)->btree);
470
471 WT_MD_CURSOR_NEEDKEY(cursor);
472 WT_MD_CURSOR_NEEDVALUE(cursor);
473
474 /*
475 * Since the key/value formats are 's' the WT_ITEMs must contain a
476 * NULL terminated string.
477 */
478 ret =
479 __wt_metadata_insert(session, cursor->key.data, cursor->value.data);
480
481 err: API_END_RET(session, ret);
482 }
483
484 /*
485 * __curmetadata_update --
486 * WT_CURSOR->update method for the metadata cursor type.
487 */
488 static int
__curmetadata_update(WT_CURSOR * cursor)489 __curmetadata_update(WT_CURSOR *cursor)
490 {
491 WT_CURSOR *file_cursor;
492 WT_CURSOR_METADATA *mdc;
493 WT_DECL_RET;
494 WT_SESSION_IMPL *session;
495
496 mdc = (WT_CURSOR_METADATA *)cursor;
497 file_cursor = mdc->file_cursor;
498 CURSOR_API_CALL(cursor, session,
499 update, ((WT_CURSOR_BTREE *)file_cursor)->btree);
500
501 WT_MD_CURSOR_NEEDKEY(cursor);
502 WT_MD_CURSOR_NEEDVALUE(cursor);
503
504 /*
505 * Since the key/value formats are 's' the WT_ITEMs must contain a
506 * NULL terminated string.
507 */
508 ret =
509 __wt_metadata_update(session, cursor->key.data, cursor->value.data);
510
511 err: API_END_RET(session, ret);
512 }
513
514 /*
515 * __curmetadata_remove --
516 * WT_CURSOR->remove method for the metadata cursor type.
517 */
518 static int
__curmetadata_remove(WT_CURSOR * cursor)519 __curmetadata_remove(WT_CURSOR *cursor)
520 {
521 WT_CURSOR *file_cursor;
522 WT_CURSOR_METADATA *mdc;
523 WT_DECL_RET;
524 WT_SESSION_IMPL *session;
525
526 mdc = (WT_CURSOR_METADATA *)cursor;
527 file_cursor = mdc->file_cursor;
528 CURSOR_API_CALL(cursor, session,
529 remove, ((WT_CURSOR_BTREE *)file_cursor)->btree);
530
531 WT_MD_CURSOR_NEEDKEY(cursor);
532
533 /*
534 * Since the key format is 's' the WT_ITEM must contain a NULL
535 * terminated string.
536 */
537 ret = __wt_metadata_remove(session, cursor->key.data);
538
539 err: API_END_RET(session, ret);
540 }
541
542 /*
543 * __curmetadata_close --
544 * WT_CURSOR->close method for the metadata cursor type.
545 */
546 static int
__curmetadata_close(WT_CURSOR * cursor)547 __curmetadata_close(WT_CURSOR *cursor)
548 {
549 WT_CURSOR *c;
550 WT_CURSOR_METADATA *mdc;
551 WT_DECL_RET;
552 WT_SESSION_IMPL *session;
553
554 mdc = (WT_CURSOR_METADATA *)cursor;
555 c = mdc->file_cursor;
556 CURSOR_API_CALL_PREPARE_ALLOWED(cursor, session, close,
557 c == NULL ? NULL : ((WT_CURSOR_BTREE *)c)->btree);
558 err:
559
560 if (c != NULL)
561 WT_TRET(c->close(c));
562 if ((c = mdc->create_cursor) != NULL)
563 WT_TRET(c->close(c));
564 __wt_cursor_close(cursor);
565
566 API_END_RET(session, ret);
567 }
568
569 /*
570 * __wt_curmetadata_open --
571 * WT_SESSION->open_cursor method for metadata cursors.
572 *
573 * Metadata cursors are a similar to a file cursor on the special metadata
574 * table, except that the metadata for the metadata table (which is stored
575 * in the turtle file) can also be queried.
576 *
577 * Metadata cursors are read-only by default.
578 */
579 int
__wt_curmetadata_open(WT_SESSION_IMPL * session,const char * uri,WT_CURSOR * owner,const char * cfg[],WT_CURSOR ** cursorp)580 __wt_curmetadata_open(WT_SESSION_IMPL *session,
581 const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp)
582 {
583 WT_CURSOR_STATIC_INIT(iface,
584 __wt_cursor_get_key, /* get-key */
585 __wt_cursor_get_value, /* get-value */
586 __wt_cursor_set_key, /* set-key */
587 __wt_cursor_set_value, /* set-value */
588 __curmetadata_compare, /* compare */
589 __wt_cursor_equals, /* equals */
590 __curmetadata_next, /* next */
591 __curmetadata_prev, /* prev */
592 __curmetadata_reset, /* reset */
593 __curmetadata_search, /* search */
594 __curmetadata_search_near, /* search-near */
595 __curmetadata_insert, /* insert */
596 __wt_cursor_modify_notsup, /* modify */
597 __curmetadata_update, /* update */
598 __curmetadata_remove, /* remove */
599 __wt_cursor_notsup, /* reserve */
600 __wt_cursor_reconfigure_notsup, /* reconfigure */
601 __wt_cursor_notsup, /* cache */
602 __wt_cursor_reopen_notsup, /* reopen */
603 __curmetadata_close); /* close */
604 WT_CURSOR *cursor;
605 WT_CURSOR_METADATA *mdc;
606 WT_DECL_RET;
607 WT_CONFIG_ITEM cval;
608
609 WT_RET(__wt_calloc_one(session, &mdc));
610 cursor = (WT_CURSOR *)mdc;
611 *cursor = iface;
612 cursor->session = (WT_SESSION *)session;
613 cursor->key_format = "S";
614 cursor->value_format = "S";
615
616 /*
617 * Open the file cursor for operations on the regular metadata; don't
618 * use the existing, cached session metadata cursor, the configuration
619 * may not be the same.
620 */
621 WT_ERR(__wt_metadata_cursor_open(session, cfg[1], &mdc->file_cursor));
622
623 /*
624 * If we are only returning create config, strip internal metadata.
625 * We'll need some extra cursors to pull out column group information
626 * and chase "source" entries.
627 */
628 if (strcmp(uri, "metadata:create") == 0) {
629 F_SET(mdc, WT_MDC_CREATEONLY);
630 WT_ERR(__wt_metadata_cursor_open(session, cfg[1],
631 &mdc->create_cursor));
632 }
633
634 WT_ERR(__wt_cursor_init(cursor, uri, owner, cfg, cursorp));
635
636 /*
637 * Metadata cursors default to readonly; if not set to not-readonly,
638 * they are permanently readonly and cannot be reconfigured.
639 */
640 WT_ERR(__wt_config_gets_def(session, cfg, "readonly", 1, &cval));
641 if (cval.val != 0) {
642 cursor->insert = __wt_cursor_notsup;
643 cursor->update = __wt_cursor_notsup;
644 cursor->remove = __wt_cursor_notsup;
645 }
646
647 if (0) {
648 err: WT_TRET(__curmetadata_close(cursor));
649 *cursorp = NULL;
650 }
651 return (ret);
652 }
653