Exemplo n.º 1
0
/*
 * __find_column_format --
 *	Find the format of the named column.
 */
static int
__find_column_format(WT_SESSION_IMPL *session, WT_TABLE *table,
    WT_CONFIG_ITEM *colname, bool value_only, WT_PACK_VALUE *pv)
{
	WT_CONFIG conf;
	WT_CONFIG_ITEM k, v;
	WT_DECL_RET;
	WT_PACK pack;
	bool inkey;

	__wt_config_subinit(session, &conf, &table->colconf);
	WT_RET(__pack_init(session, &pack, table->key_format));
	inkey = true;

	while ((ret = __wt_config_next(&conf, &k, &v)) == 0) {
		if ((ret = __pack_next(&pack, pv)) == WT_NOTFOUND && inkey) {
			ret = __pack_init(session, &pack, table->value_format);
			if (ret == 0)
				ret = __pack_next(&pack, pv);
			inkey = false;
		}
		if (ret != 0)
			return (ret);

		if (k.len == colname->len &&
		    strncmp(colname->str, k.str, k.len) == 0) {
			if (value_only && inkey)
				return (__wt_set_return(session, EINVAL));
			return (0);
		}
	}

	return (ret);
}
Exemplo n.º 2
0
/*
 * __wt_struct_packv --
 *	Pack a byte string (va_list version).
 */
int
__wt_struct_packv(WT_SESSION_IMPL *session,
    void *buffer, size_t size, const char *fmt, va_list ap)
{
	WT_DECL_RET;
	WT_PACK pack;
	WT_PACK_VALUE pv;
	uint8_t *p, *end;

	WT_CLEAR(pv);		/* -Wuninitialized */

	WT_RET(__pack_init(session, &pack, fmt));

	p = buffer;
	end = p + size;

	while ((ret = __pack_next(&pack, &pv)) == 0) {
		WT_PACK_GET(session, pv, ap);
		WT_RET(__pack_write(session, &pv, &p, (size_t)(end - p)));
	}

	WT_ASSERT(session, p <= end);

	if (ret != WT_NOTFOUND)
		return (ret);

	return (0);
}
Exemplo n.º 3
0
/*
 * __wt_struct_unpackv --
 *	Unpack a byte string (va_list version).
 */
int
__wt_struct_unpackv(WT_SESSION_IMPL *session,
    const void *buffer, size_t size, const char *fmt, va_list ap)
{
	WT_DECL_RET;
	WT_PACK pack;
	WT_PACK_VALUE pv;
	const uint8_t *p, *end;

	WT_RET(__pack_init(session, &pack, fmt));

	p = buffer;
	end = p + size;
	WT_CLEAR(pv.u.item);			/* GCC 4.6 lint */

	while ((ret = __pack_next(&pack, &pv)) == 0) {
		WT_RET(__unpack_read(session, &pv, &p, (size_t)(end - p)));
		WT_UNPACK_PUT(session, pv, ap);
	}

	WT_ASSERT(session, p <= end);

	if (ret != WT_NOTFOUND)
		return (ret);

	return (0);
}
Exemplo n.º 4
0
/*
 * __wt_struct_unpack_size --
 *	Determine the packed size of a buffer matching the format.
 */
int
__wt_struct_unpack_size(WT_SESSION_IMPL *session,
    const void *buffer, size_t size, const char *fmt, size_t *resultp)
{
	WT_DECL_PACK_VALUE(pv);
	WT_DECL_RET;
	WT_PACK pack;
	const uint8_t *p, *end;

	p = buffer;
	end = p + size;

	WT_RET(__pack_init(session, &pack, fmt));
	while ((ret = __pack_next(&pack, &pv)) == 0)
		WT_RET(__unpack_read(session, &pv, &p, (size_t)(end - p)));

	/* Be paranoid - __pack_write should never overflow. */
	WT_ASSERT(session, p <= end);

	if (ret != WT_NOTFOUND)
		return (ret);

	*resultp = WT_PTRDIFF(p, buffer);
	return (0);
}
Exemplo n.º 5
0
/*
 * __wt_struct_repack --
 *	Return the subset of the packed buffer that represents part of
 *	the format.  If the result is not contiguous in the existing
 *	buffer, a buffer is reallocated and filled.
 */
int
__wt_struct_repack(WT_SESSION_IMPL *session, const char *infmt,
    const char *outfmt, const WT_ITEM *inbuf, WT_ITEM *outbuf)
{
	WT_DECL_PACK_VALUE(pvin);
	WT_DECL_PACK_VALUE(pvout);
	WT_DECL_RET;
	WT_PACK packin, packout;
	const uint8_t *before, *end, *p;
	const void *start;

	start = NULL;
	p = inbuf->data;
	end = p + inbuf->size;

	WT_RET(__pack_init(session, &packout, outfmt));
	WT_RET(__pack_init(session, &packin, infmt));

	/* Outfmt should complete before infmt */
	while ((ret = __pack_next(&packout, &pvout)) == 0) {
		if (p >= end)
			WT_RET(EINVAL);
		if (pvout.type == 'x' && pvout.size == 0 && pvout.havesize)
			continue;
		WT_RET(__pack_next(&packin, &pvin));
		before = p;
		WT_RET(__unpack_read(session, &pvin, &p, (size_t)(end - p)));
		if (pvout.type != pvin.type)
			WT_RET(ENOTSUP);
		if (start == NULL)
			start = before;
	}
	WT_RET_NOTFOUND_OK(ret);

	/* Be paranoid - __pack_write should never overflow. */
	WT_ASSERT(session, p <= end);

	outbuf->data = start;
	outbuf->size = WT_PTRDIFF(p, start);

	return (0);
}
Exemplo n.º 6
0
/*
 * __wt_schema_colcheck --
 *	Check that a list of columns matches a (key,value) format pair.
 */
int
__wt_schema_colcheck(WT_SESSION_IMPL *session,
    const char *key_format, const char *value_format, WT_CONFIG_ITEM *colconf,
    u_int *kcolsp, u_int *vcolsp)
{
	WT_CONFIG conf;
	WT_CONFIG_ITEM k, v;
	WT_DECL_PACK_VALUE(pv);
	WT_DECL_RET;
	WT_PACK pack;
	u_int kcols, ncols, vcols;

	WT_RET(__pack_init(session, &pack, key_format));
	for (kcols = 0; (ret = __pack_next(&pack, &pv)) == 0; kcols++)
		;
	WT_RET_NOTFOUND_OK(ret);

	WT_RET(__pack_init(session, &pack, value_format));
	for (vcols = 0; (ret = __pack_next(&pack, &pv)) == 0; vcols++)
		;
	WT_RET_TEST(ret != WT_NOTFOUND, ret);

	/* Walk through the named columns. */
	__wt_config_subinit(session, &conf, colconf);
	for (ncols = 0; (ret = __wt_config_next(&conf, &k, &v)) == 0; ncols++)
		;
	WT_RET_TEST(ret != WT_NOTFOUND, ret);

	if (ncols != 0 && ncols != kcols + vcols)
		WT_RET_MSG(session, EINVAL, "Number of columns in '%.*s' "
		    "does not match key format '%s' plus value format '%s'",
		    (int)colconf->len, colconf->str, key_format, value_format);

	if (kcolsp != NULL)
		*kcolsp = kcols;
	if (vcolsp != NULL)
		*vcolsp = vcols;

	return (0);
}
Exemplo n.º 7
0
/*
 * __json_struct_unpackv --
 *	Unpack a byte string to JSON (va_list version).
 */
static inline int
__json_struct_unpackv(WT_SESSION_IMPL *session,
    const void *buffer, size_t size, const char *fmt, WT_CONFIG_ITEM *names,
    u_char *jbuf, size_t jbufsize, bool iskey, va_list ap)
{
	WT_CONFIG_ITEM name;
	WT_DECL_PACK_VALUE(pv);
	WT_DECL_RET;
	WT_PACK pack;
	WT_PACK_NAME packname;
	size_t jsize;
	bool needcr;
	const uint8_t *p, *end;

	p = buffer;
	end = p + size;
	needcr = false;

	/* Unpacking a cursor marked as json implies a single arg. */
	*va_arg(ap, const char **) = (char *)jbuf;

	WT_RET(__pack_name_init(session, names, iskey, &packname));
	WT_RET(__pack_init(session, &pack, fmt));
	while ((ret = __pack_next(&pack, &pv)) == 0) {
		if (needcr) {
			WT_ASSERT(session, jbufsize >= 3);
			strncat((char *)jbuf, ",\n", jbufsize);
			jbuf += 2;
			jbufsize -= 2;
		}
		needcr = true;
		WT_RET(__unpack_read(session, &pv, &p, (size_t)(end - p)));
		WT_RET(__pack_name_next(&packname, &name));
		jsize = __json_unpack_put(session,
		    (u_char *)&pv, jbuf, jbufsize, &name);
		WT_ASSERT(session, jsize <= jbufsize);
		jbuf += jsize;
		jbufsize -= jsize;
	}
	if (ret == WT_NOTFOUND)
		ret = 0;

	/* Be paranoid - __unpack_read should never overflow. */
	WT_ASSERT(session, p <= end);

	WT_ASSERT(session, jbufsize == 1);

	return (ret);
}
Exemplo n.º 8
0
/*
 * __wt_struct_sizev --
 *	Calculate the size of a packed byte string (va_list version).
 */
int
__wt_struct_sizev(
    WT_SESSION_IMPL *session, size_t *sizep, const char *fmt, va_list ap)
{
	WT_PACK pack;
	WT_PACK_VALUE pv;
	size_t total;

	WT_CLEAR(pv);		/* -Wuninitialized */

	WT_RET(__pack_init(session, &pack, fmt));

	for (total = 0; __pack_next(&pack, &pv) == 0;) {
		WT_PACK_GET(session, pv, ap);
		total += __pack_size(session, &pv);
	}
	*sizep = total;
	return (0);
}
Exemplo n.º 9
0
/*
 * __wt_struct_truncate --
 *	Return a packing string for the first N columns in a value.
 */
int
__wt_struct_truncate(WT_SESSION_IMPL *session,
    const char *input_fmt, u_int ncols, WT_ITEM *format)
{
	WT_DECL_PACK_VALUE(pv);
	WT_PACK pack;

	WT_RET(__pack_init(session, &pack, input_fmt));
	while (ncols-- > 0) {
		WT_RET(__pack_next(&pack, &pv));
		if (pv.havesize)
			WT_RET(__wt_buf_catfmt(session,
			    format, "%" PRIu32 "%c", pv.size, pv.type));
		else
			WT_RET(__wt_buf_catfmt(session, format, "%c", pv.type));
	}

	return (0);
}
Exemplo n.º 10
0
/*
 * wiredtiger_pack_start --
 *	Open a stream for packing.
 */
int
wiredtiger_pack_start(WT_SESSION *wt_session,
	const char *format, void *buffer, size_t len, WT_PACK_STREAM **psp)
{
	WT_DECL_RET;
	WT_PACK_STREAM *ps;
	WT_SESSION_IMPL *session;

	session = (WT_SESSION_IMPL *)wt_session;
	WT_RET(__wt_calloc_one(session, &ps));
	WT_ERR(__pack_init(session, &ps->pack, format));
	ps->p = ps->start = buffer;
	ps->end = ps->p + len;
	*psp = ps;

	if (0) {
err:		(void)wiredtiger_pack_close(ps, NULL);
	}
	return (ret);
}
Exemplo n.º 11
0
/*
 * __wt_struct_truncate --
 *	Return a packing string for the first N columns in a value.
 */
int
__wt_struct_truncate(WT_SESSION_IMPL *session,
    const char *input_fmt, u_int ncols, WT_ITEM *format)
{
	WT_PACK pack;
	WT_PACK_VALUE pv;

	WT_CLEAR(pv);   /* -Wuninitialized */

	WT_RET(__pack_init(session, &pack, input_fmt));
	while (ncols-- > 0) {
		WT_RET(__pack_next(&pack, &pv));
		if (pv.havesize)
			WT_RET(__wt_buf_catfmt(
			    session, format, "%d%c", (int)pv.size, pv.type));
		else
			WT_RET(__wt_buf_catfmt(session, format, "%c", pv.type));
	}

	return (0);
}
Exemplo n.º 12
0
/*
 * __json_struct_size --
 *	Calculate the size of a packed byte string as formatted for JSON.
 */
static inline int
__json_struct_size(WT_SESSION_IMPL *session, const void *buffer,
    size_t size, const char *fmt, WT_CONFIG_ITEM *names, bool iskey,
    size_t *presult)
{
	WT_CONFIG_ITEM name;
	WT_DECL_PACK_VALUE(pv);
	WT_DECL_RET;
	WT_PACK pack;
	WT_PACK_NAME packname;
	size_t result;
	bool needcr;
	const uint8_t *p, *end;

	p = buffer;
	end = p + size;
	result = 0;
	needcr = false;

	WT_RET(__pack_name_init(session, names, iskey, &packname));
	WT_RET(__pack_init(session, &pack, fmt));
	while ((ret = __pack_next(&pack, &pv)) == 0) {
		if (needcr)
			result += 2;
		needcr = true;
		WT_RET(__unpack_read(session, &pv, &p, (size_t)(end - p)));
		WT_RET(__pack_name_next(&packname, &name));
		result += __json_unpack_put(session, &pv, NULL, 0, &name);
	}
	if (ret == WT_NOTFOUND)
		ret = 0;

	/* Be paranoid - __pack_write should never overflow. */
	WT_ASSERT(session, p <= end);

	*presult = result;
	return (ret);
}
Exemplo n.º 13
0
/*
 * __wt_struct_repack --
 *	Return the subset of the packed buffer that represents part of
 *	the format.  If the result is not contiguous in the existing
 *	buffer, a buffer is reallocated and filled.
 */
int
__wt_struct_repack(WT_SESSION_IMPL *session, const char *infmt,
    const char *outfmt, const WT_ITEM *inbuf, WT_ITEM *outbuf,
    void **reallocp)
{
	WT_DECL_PACK_VALUE(pvin);
	WT_DECL_PACK_VALUE(pvout);
	WT_DECL_RET;
	WT_PACK packin, packout;
	const uint8_t *before, *end, *p;
	uint8_t *newbuf, *pout;
	size_t len;
	const void *start;

	start = newbuf = NULL;
	p = inbuf->data;
	end = p + inbuf->size;

	/*
	 * Handle this non-contiguous case: 'U' -> 'u' at the end of the buf.
	 * The former case has the size embedded before the item, the latter
	 * does not.
	 */
	if ((len = strlen(outfmt)) > 1 && outfmt[len - 1] == 'u' &&
	    strlen(infmt) > len && infmt[len - 1] == 'U') {
		WT_ERR(__wt_realloc(session, NULL, inbuf->size, reallocp));
		pout = *reallocp;
	} else
		pout = NULL;

	WT_ERR(__pack_init(session, &packout, outfmt));
	WT_ERR(__pack_init(session, &packin, infmt));

	/* Outfmt should complete before infmt */
	while ((ret = __pack_next(&packout, &pvout)) == 0) {
		WT_ERR(__pack_next(&packin, &pvin));
		before = p;
		WT_ERR(__unpack_read(session, &pvin, &p, (size_t)(end - p)));
		if (pvout.type != pvin.type) {
			if (pvout.type == 'u' && pvin.type == 'U') {
				/* Skip the prefixed size, we don't need it */
				WT_ERR(__wt_struct_unpack_size(session, before,
				    (size_t)(end - before), "I", &len));
				before += len;
			} else
				WT_ERR(ENOTSUP);
		}
		if (pout != NULL) {
			memcpy(pout, before, WT_PTRDIFF(p, before));
			pout += p - before;
		} else if (start == NULL)
			start = before;
	}
	WT_ERR_NOTFOUND_OK(ret);

	/* Be paranoid - __pack_write should never overflow. */
	WT_ASSERT(session, p <= end);

	if (pout != NULL) {
		outbuf->data = *reallocp;
		outbuf->size = WT_PTRDIFF(pout, *reallocp);
	} else {
		outbuf->data = start;
		outbuf->size = WT_PTRDIFF(p, start);
	}

err:	return (ret);
}
Exemplo n.º 14
0
/*
 * __wt_schema_project_merge --
 *	Given list of cursors and a projection, build a buffer containing the
 *	column values read from the cursors.
 */
int
__wt_schema_project_merge(WT_SESSION_IMPL *session,
    WT_CURSOR **cp, const char *proj_arg, const char *vformat, WT_ITEM *value)
{
	WT_CURSOR *c;
	WT_ITEM *buf;
	WT_PACK pack, vpack;
	WT_PACK_VALUE pv, vpv;
	char *proj;
	uint8_t *p, *end, *vp;
	size_t len;
	uint32_t arg;

	WT_CLEAR(pack);         /* -Wuninitialized */
	WT_CLEAR(pv);           /* -Wuninitialized */
	WT_CLEAR(vpv);          /* -Wuninitialized */
	p = end = NULL;         /* -Wuninitialized */

	WT_RET(__wt_buf_init(session, value, 0));
	WT_RET(__pack_init(session, &vpack, vformat));

	for (proj = (char *)proj_arg; *proj != '\0'; proj++) {
		arg = (uint32_t)strtoul(proj, &proj, 10);

		switch (*proj) {
		case WT_PROJ_KEY:
			c = cp[arg];
			if (WT_CURSOR_RECNO(c)) {
				c->key.data = &c->recno;
				c->key.size = sizeof(c->recno);
				WT_RET(__pack_init(session, &pack, "R"));
			} else
				WT_RET(__pack_init(
				    session, &pack, c->key_format));
			buf = &c->key;
			p = (uint8_t *)buf->data;
			end = p + buf->size;
			continue;

		case WT_PROJ_VALUE:
			c = cp[arg];
			WT_RET(__pack_init(session, &pack, c->value_format));
			buf = &c->value;
			p = (uint8_t *)buf->data;
			end = p + buf->size;
			continue;
		}

		/*
		 * Otherwise, the argument is a count, where a missing
		 * count means a count of 1.
		 */
		for (arg = (arg == 0) ? 1 : arg; arg > 0; arg--) {
			switch (*proj) {
			case WT_PROJ_NEXT:
			case WT_PROJ_SKIP:
				WT_RET(__pack_next(&pack, &pv));
				WT_RET(__unpack_read(session, &pv,
				    (const uint8_t **)&p,
				    (size_t)(end - p)));
				if (*proj == WT_PROJ_SKIP)
					break;

				WT_RET(__pack_next(&vpack, &vpv));
				vpv.u = pv.u;
				len = __pack_size(session, &vpv);
				WT_RET(__wt_buf_grow(session,
				    value, value->size + len));
				vp = (uint8_t *)value->data + value->size;
				WT_RET(__pack_write(session, &vpv, &vp, len));
				value->size += WT_STORE_SIZE(len);
				/* FALLTHROUGH */

			case WT_PROJ_REUSE:
				/* Don't copy the same value twice. */
				break;
			}
		}
	}

	return (0);
}
Exemplo n.º 15
0
/*
 * __wt_schema_project_merge --
 *	Given list of cursors and a projection, build a buffer containing the
 *	column values read from the cursors.
 */
int
__wt_schema_project_merge(WT_SESSION_IMPL *session,
    WT_CURSOR **cp, const char *proj_arg, const char *vformat, WT_ITEM *value)
{
	WT_CURSOR *c;
	WT_DECL_PACK(pack);
	WT_DECL_PACK_VALUE(pv);
	WT_DECL_PACK_VALUE(vpv);
	WT_ITEM *buf;
	WT_PACK vpack;
	u_long arg;
	char *proj;
	const uint8_t *p, *end;
	uint8_t *vp;
	size_t len;

	p = end = NULL;		/* -Wuninitialized */

	WT_RET(__wt_buf_init(session, value, 0));
	WT_RET(__pack_init(session, &vpack, vformat));

	for (proj = (char *)proj_arg; *proj != '\0'; proj++) {
		arg = strtoul(proj, &proj, 10);

		switch (*proj) {
		case WT_PROJ_KEY:
			c = cp[arg];
			if (WT_CURSOR_RECNO(c)) {
				c->key.data = &c->recno;
				c->key.size = sizeof(c->recno);
				WT_RET(__pack_init(session, &pack, "R"));
			} else
				WT_RET(__pack_init(
				    session, &pack, c->key_format));
			buf = &c->key;
			p = buf->data;
			end = p + buf->size;
			continue;

		case WT_PROJ_VALUE:
			c = cp[arg];
			WT_RET(__pack_init(session, &pack, c->value_format));
			buf = &c->value;
			p = buf->data;
			end = p + buf->size;
			continue;
		}

		/*
		 * Otherwise, the argument is a count, where a missing
		 * count means a count of 1.
		 */
		for (arg = (arg == 0) ? 1 : arg; arg > 0; arg--) {
			switch (*proj) {
			case WT_PROJ_NEXT:
			case WT_PROJ_SKIP:
			case WT_PROJ_REUSE:
				WT_RET(__pack_next(&pack, &pv));
				WT_RET(__unpack_read(session, &pv,
				    &p, (size_t)(end - p)));
				/* Only copy the value out once. */
				if (*proj != WT_PROJ_NEXT)
					break;

				WT_RET(__pack_next(&vpack, &vpv));
				/* Make sure the types are compatible. */
				WT_ASSERT(session,
				    __wt_tolower((u_char)pv.type) ==
				    __wt_tolower((u_char)vpv.type));
				vpv.u = pv.u;
				WT_RET(__pack_size(session, &vpv, &len));
				WT_RET(__wt_buf_grow(session,
				    value, value->size + len));
				vp = (uint8_t *)value->mem + value->size;
				WT_RET(__pack_write(session, &vpv, &vp, len));
				value->size += len;
				break;
			}
		}
	}

	return (0);
}
Exemplo n.º 16
0
/*
 * __wt_schema_project_slice --
 *	Given list of cursors and a projection, read columns from the
 *	a raw buffer.
 */
int
__wt_schema_project_slice(WT_SESSION_IMPL *session, WT_CURSOR **cp,
    const char *proj_arg, bool key_only, const char *vformat, WT_ITEM *value)
{
	WT_CURSOR *c;
	WT_DECL_ITEM(buf);
	WT_DECL_PACK(pack);
	WT_DECL_PACK_VALUE(pv);
	WT_DECL_PACK_VALUE(vpv);
	WT_PACK vpack;
	u_long arg;
	char *proj;
	uint8_t *end, *p;
	const uint8_t *next, *vp, *vend;
	size_t len, offset, old_len;
	bool skip;

	p = end = NULL;		/* -Wuninitialized */

	WT_RET(__pack_init(session, &vpack, vformat));
	vp = value->data;
	vend = vp + value->size;

	/* Reset any of the buffers we will be setting. */
	for (proj = (char *)proj_arg; *proj != '\0'; proj++) {
		arg = strtoul(proj, &proj, 10);
		if (*proj == WT_PROJ_KEY) {
			c = cp[arg];
			WT_RET(__wt_buf_init(session, &c->key, 0));
		} else if (*proj == WT_PROJ_VALUE && !key_only) {
			c = cp[arg];
			WT_RET(__wt_buf_init(session, &c->value, 0));
		}
	}

	skip = key_only;
	for (proj = (char *)proj_arg; *proj != '\0'; proj++) {
		arg = strtoul(proj, &proj, 10);

		switch (*proj) {
		case WT_PROJ_KEY:
			skip = false;
			c = cp[arg];
			if (WT_CURSOR_RECNO(c)) {
				c->key.data = &c->recno;
				c->key.size = sizeof(c->recno);
				WT_RET(__pack_init(session, &pack, "R"));
			} else
				WT_RET(__pack_init(
				    session, &pack, c->key_format));
			buf = &c->key;
			p = (uint8_t *)buf->data;
			end = p + buf->size;
			continue;

		case WT_PROJ_VALUE:
			skip = key_only;
			if (skip)
				continue;
			c = cp[arg];
			WT_RET(__pack_init(session, &pack, c->value_format));
			buf = &c->value;
			p = (uint8_t *)buf->data;
			end = p + buf->size;
			continue;
		}

		/* We have to get a key or value before any operations. */
		WT_ASSERT(session, skip || buf != NULL);

		/*
		 * Otherwise, the argument is a count, where a missing
		 * count means a count of 1.
		 */
		for (arg = (arg == 0) ? 1 : arg; arg > 0; arg--) {
			switch (*proj) {
			case WT_PROJ_SKIP:
				if (skip)
					break;
				WT_RET(__pack_next(&pack, &pv));

				/*
				 * A nasty case: if we are inserting
				 * out-of-order, append a zero value to keep
				 * the buffer in the correct format.
				 */
				if (p == end) {
					/* Set up an empty value. */
					WT_CLEAR(pv.u);
					if (pv.type == 'S' || pv.type == 's')
						pv.u.s = "";

					WT_RET(__pack_size(session, &pv, &len));
					WT_RET(__wt_buf_grow(session,
					    buf, buf->size + len));
					p = (uint8_t *)buf->data + buf->size;
					WT_RET(__pack_write(
					    session, &pv, &p, len));
					end = p;
					buf->size += len;
				} else
					WT_RET(__unpack_read(session,
					    &pv, (const uint8_t **)&p,
					    (size_t)(end - p)));
				break;

			case WT_PROJ_NEXT:
				WT_RET(__pack_next(&vpack, &vpv));
				WT_RET(__unpack_read(session, &vpv,
				    &vp, (size_t)(vend - vp)));
				/* FALLTHROUGH */

			case WT_PROJ_REUSE:
				if (skip)
					break;

				/*
				 * Read the item we're about to overwrite.
				 *
				 * There is subtlety here: the value format
				 * may not exactly match the cursor's format.
				 * In particular, we need lengths with raw
				 * columns in the middle of a packed struct,
				 * but not if they are at the end of a struct.
				 */
				WT_RET(__pack_next(&pack, &pv));

				next = p;
				if (p < end)
					WT_RET(__unpack_read(session, &pv,
					    &next, (size_t)(end - p)));
				old_len = (size_t)(next - p);

				/* Make sure the types are compatible. */
				WT_ASSERT(session,
				    __wt_tolower((u_char)pv.type) ==
				    __wt_tolower((u_char)vpv.type));
				pv.u = vpv.u;

				WT_RET(__pack_size(session, &pv, &len));
				offset = WT_PTRDIFF(p, buf->data);
				/*
				 * Avoid growing the buffer if the value fits.
				 * This is not just a performance issue: it
				 * covers the case of record number keys, which
				 * have to be written to cursor->recno.
				 */
				if (len > old_len)
					WT_RET(__wt_buf_grow(session,
					    buf, buf->size + len - old_len));
				p = (uint8_t *)buf->data + offset;
				/* Make room if we're inserting out-of-order. */
				if (offset + old_len < buf->size)
					memmove(p + len, p + old_len,
					    buf->size - (offset + old_len));
				WT_RET(__pack_write(session, &pv, &p, len));
				buf->size += len - old_len;
				end = (uint8_t *)buf->data + buf->size;
				break;
			default:
				WT_RET_MSG(session, EINVAL,
				    "unexpected projection plan: %c",
				    (int)*proj);
			}
		}
	}

	return (0);
}
Exemplo n.º 17
0
/*
 * __wt_schema_project_out --
 *	Given list of cursors and a projection, read columns from the
 *	dependent cursors and return them to the application.
 */
int
__wt_schema_project_out(WT_SESSION_IMPL *session,
    WT_CURSOR **cp, const char *proj_arg, va_list ap)
{
	WT_CURSOR *c;
	WT_DECL_PACK(pack);
	WT_DECL_PACK_VALUE(pv);
	u_long arg;
	char *proj;
	uint8_t *p, *end;

	p = end = NULL;		/* -Wuninitialized */

	for (proj = (char *)proj_arg; *proj != '\0'; proj++) {
		arg = strtoul(proj, &proj, 10);

		switch (*proj) {
		case WT_PROJ_KEY:
			c = cp[arg];
			if (WT_CURSOR_RECNO(c)) {
				c->key.data = &c->recno;
				c->key.size = sizeof(c->recno);
				WT_RET(__pack_init(session, &pack, "R"));
			} else
				WT_RET(__pack_init(
				    session, &pack, c->key_format));
			p = (uint8_t *)c->key.data;
			end = p + c->key.size;
			continue;

		case WT_PROJ_VALUE:
			c = cp[arg];
			WT_RET(__pack_init(session, &pack, c->value_format));
			p = (uint8_t *)c->value.data;
			end = p + c->value.size;
			continue;
		}

		/*
		 * Otherwise, the argument is a count, where a missing
		 * count means a count of 1.
		 */
		for (arg = (arg == 0) ? 1 : arg; arg > 0; arg--) {
			switch (*proj) {
			case WT_PROJ_NEXT:
			case WT_PROJ_SKIP:
			case WT_PROJ_REUSE:
				WT_RET(__pack_next(&pack, &pv));
				WT_RET(__unpack_read(session, &pv,
				    (const uint8_t **)&p, (size_t)(end - p)));
				/* Only copy the value out once. */
				if (*proj != WT_PROJ_NEXT)
					break;
				WT_UNPACK_PUT(session, pv, ap);
				break;
			}
		}
	}

	return (0);
}
Exemplo n.º 18
0
/*
 * __wt_schema_project_in --
 *	Given list of cursors and a projection, read columns from the
 *	application into the dependent cursors.
 */
int
__wt_schema_project_in(WT_SESSION_IMPL *session,
    WT_CURSOR **cp, const char *proj_arg, va_list ap)
{
	WT_CURSOR *c;
	WT_DECL_ITEM(buf);
	WT_DECL_PACK(pack);
	WT_DECL_PACK_VALUE(pv);
	WT_PACK_VALUE old_pv;
	size_t len, offset, old_len;
	u_long arg;
	char *proj;
	uint8_t *p, *end;
	const uint8_t *next;

	p = end = NULL;		/* -Wuninitialized */

	/* Reset any of the buffers we will be setting. */
	for (proj = (char *)proj_arg; *proj != '\0'; proj++) {
		arg = strtoul(proj, &proj, 10);
		if (*proj == WT_PROJ_KEY) {
			c = cp[arg];
			WT_RET(__wt_buf_init(session, &c->key, 0));
		} else if (*proj == WT_PROJ_VALUE) {
			c = cp[arg];
			WT_RET(__wt_buf_init(session, &c->value, 0));
		}
	}

	for (proj = (char *)proj_arg; *proj != '\0'; proj++) {
		arg = strtoul(proj, &proj, 10);

		switch (*proj) {
		case WT_PROJ_KEY:
			c = cp[arg];
			if (WT_CURSOR_RECNO(c)) {
				c->key.data = &c->recno;
				c->key.size = sizeof(c->recno);
				WT_RET(__pack_init(session, &pack, "R"));
			} else
				WT_RET(__pack_init(
				    session, &pack, c->key_format));
			buf = &c->key;
			p = (uint8_t *)buf->data;
			end = p + buf->size;
			continue;

		case WT_PROJ_VALUE:
			c = cp[arg];
			WT_RET(__pack_init(session, &pack, c->value_format));
			buf = &c->value;
			p = (uint8_t *)buf->data;
			end = p + buf->size;
			continue;
		}

		/* We have to get a key or value before any operations. */
		WT_ASSERT(session, buf != NULL);

		/*
		 * Otherwise, the argument is a count, where a missing
		 * count means a count of 1.
		 */
		for (arg = (arg == 0) ? 1 : arg; arg > 0; arg--) {
			switch (*proj) {
			case WT_PROJ_SKIP:
				WT_RET(__pack_next(&pack, &pv));
				/*
				 * A nasty case: if we are inserting
				 * out-of-order, we may reach the end of the
				 * data.  That's okay: we want to append in
				 * that case, and we're positioned to do that.
				 */
				if (p == end) {
					/* Set up an empty value. */
					WT_CLEAR(pv.u);
					if (pv.type == 'S' || pv.type == 's')
						pv.u.s = "";

					WT_RET(__pack_size(session, &pv, &len));
					WT_RET(__wt_buf_grow(session,
					    buf, buf->size + len));
					p = (uint8_t *)buf->mem + buf->size;
					WT_RET(__pack_write(
					    session, &pv, &p, len));
					buf->size += len;
					end = (uint8_t *)buf->mem + buf->size;
				} else if (*proj == WT_PROJ_SKIP)
					WT_RET(__unpack_read(session,
					    &pv, (const uint8_t **)&p,
					    (size_t)(end - p)));
				break;

			case WT_PROJ_NEXT:
				WT_RET(__pack_next(&pack, &pv));
				WT_PACK_GET(session, pv, ap);
				/* FALLTHROUGH */

			case WT_PROJ_REUSE:
				/* Read the item we're about to overwrite. */
				next = p;
				if (p < end) {
					old_pv = pv;
					WT_RET(__unpack_read(session, &old_pv,
					    &next, (size_t)(end - p)));
				}
				old_len = (size_t)(next - p);

				WT_RET(__pack_size(session, &pv, &len));
				offset = WT_PTRDIFF(p, buf->mem);
				WT_RET(__wt_buf_grow(session,
				    buf, buf->size + len));
				p = (uint8_t *)buf->mem + offset;
				end = (uint8_t *)buf->mem + buf->size + len;
				/* Make room if we're inserting out-of-order. */
				if (offset + old_len < buf->size)
					memmove(p + len, p + old_len,
					    buf->size - (offset + old_len));
				WT_RET(__pack_write(session, &pv, &p, len));
				buf->size += len;
				break;

			default:
				WT_RET_MSG(session, EINVAL,
				    "unexpected projection plan: %c",
				    (int)*proj);
			}
		}
	}

	return (0);
}
Exemplo n.º 19
0
/*
 * __wt_schema_project_slice --
 *	Given list of cursors and a projection, read columns from the
 *	a raw buffer.
 */
int
__wt_schema_project_slice(WT_SESSION_IMPL *session, WT_CURSOR **cp,
    const char *proj_arg, int key_only, const char *vformat, WT_ITEM *value)
{
	WT_CURSOR *c;
	WT_ITEM *buf;
	WT_PACK pack, vpack;
	WT_PACK_VALUE pv, vpv;
	char *proj;
	uint8_t *end, *p;
	const uint8_t *next, *vp, *vend;
	size_t len, offset, old_len;
	uint32_t arg;
	int skip;

	WT_CLEAR(pack);         /* -Wuninitialized */
	WT_CLEAR(vpv);          /* -Wuninitialized */
	buf = NULL;             /* -Wuninitialized */
	p = end = NULL;         /* -Wuninitialized */

	WT_RET(__pack_init(session, &vpack, vformat));
	vp = (uint8_t *)value->data;
	vend = vp + value->size;

	/* Reset any of the buffers we will be setting. */
	for (proj = (char *)proj_arg; *proj != '\0'; proj++) {
		arg = (uint32_t)strtoul(proj, &proj, 10);
		if (*proj == WT_PROJ_KEY) {
			c = cp[arg];
			WT_RET(__wt_buf_init(session, &c->key, 0));
		} else if (*proj == WT_PROJ_VALUE && !key_only) {
			c = cp[arg];
			WT_RET(__wt_buf_init(session, &c->value, 0));
		}
	}

	skip = key_only;
	for (proj = (char *)proj_arg; *proj != '\0'; proj++) {
		arg = (uint32_t)strtoul(proj, &proj, 10);

		switch (*proj) {
		case WT_PROJ_KEY:
			skip = 0;
			c = cp[arg];
			if (WT_CURSOR_RECNO(c)) {
				c->key.data = &c->recno;
				c->key.size = sizeof(c->recno);
				WT_RET(__pack_init(session, &pack, "R"));
			} else
				WT_RET(__pack_init(
				    session, &pack, c->key_format));
			buf = &c->key;
			p = (uint8_t *)buf->data;
			end = p + buf->size;
			continue;

		case WT_PROJ_VALUE:
			if ((skip = key_only) != 0)
				continue;
			c = cp[arg];
			WT_RET(__pack_init(session, &pack, c->value_format));
			buf = &c->value;
			p = (uint8_t *)buf->data;
			end = p + buf->size;
			continue;
		}

		/*
		 * Otherwise, the argument is a count, where a missing
		 * count means a count of 1.
		 */
		for (arg = (arg == 0) ? 1 : arg; arg > 0; arg--) {
			switch (*proj) {
			case WT_PROJ_NEXT:
			case WT_PROJ_SKIP:
				if (!skip) {
					WT_RET(__pack_next(&pack, &pv));

					/*
					 * A nasty case: if we are inserting
					 * out-of-order, append a zero value
					 * to keep the buffer in the correct
					 * format.
					 */
					if (*proj == WT_PROJ_SKIP &&
					    p == end) {
						/* Set up an empty value. */
						WT_CLEAR(pv.u);
						if (pv.type == 'S' ||
						    pv.type == 's')
							pv.u.s = "";

						len = __pack_size(session, &pv);
						WT_RET(__wt_buf_grow(session,
						    buf, buf->size + len));
						p = (uint8_t *)buf->data +
						    buf->size;
						WT_RET(__pack_write(
						    session, &pv, &p, len));
						end = p;
						buf->size += WT_STORE_SIZE(len);
					} else if (*proj == WT_PROJ_SKIP)
						WT_RET(__unpack_read(session,
						    &pv, (const uint8_t **)&p,
						    (size_t)(end - p)));
				}
				if (*proj == WT_PROJ_SKIP)
					break;
				WT_RET(__pack_next(&vpack, &vpv));
				WT_RET(__unpack_read(session, &vpv,
				    &vp, (size_t)(vend - vp)));
				/* FALLTHROUGH */
			case WT_PROJ_REUSE:
				if (skip)
					break;

				/* Read the item we're about to overwrite. */
				next = p;
				if (p < end)
					WT_RET(__unpack_read(session, &pv,
					    &next, (size_t)(end - p)));
				old_len = (size_t)(next - p);

				/*
				 * There is subtlety here: the value format
				 * may not exactly match the cursor's format.
				 * In particular, we need lengths with raw
				 * columns in the middle of a packed struct,
				 * but not if they are at the end of a column.
				 */
				pv.u = vpv.u;

				len = __pack_size(session, &pv);
				offset = WT_PTRDIFF(p, buf->data);
				WT_RET(__wt_buf_grow(session,
				    buf, buf->size + len - old_len));
				p = (uint8_t *)buf->data + offset;
				/* Make room if we're inserting out-of-order. */
				if (offset + old_len < buf->size)
					memmove(p + len, p + old_len,
					    buf->size - (offset + old_len));
				WT_RET(__pack_write(session, &pv, &p, len));
				buf->size += WT_STORE_SIZE(len - old_len);
				end = (uint8_t *)buf->data + buf->size;
				break;
			default:
				WT_RET_MSG(session, EINVAL,
				    "unexpected projection plan: %c",
				    (int)*proj);
			}
		}
	}

	return (0);
}