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