/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * 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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }