diff options
Diffstat (limited to 'src/third_party/wiredtiger/src/utilities/util_load_json.c')
-rw-r--r-- | src/third_party/wiredtiger/src/utilities/util_load_json.c | 979 |
1 files changed, 474 insertions, 505 deletions
diff --git a/src/third_party/wiredtiger/src/utilities/util_load_json.c b/src/third_party/wiredtiger/src/utilities/util_load_json.c index 555704e3822..2e97c7aed0e 100644 --- a/src/third_party/wiredtiger/src/utilities/util_load_json.c +++ b/src/third_party/wiredtiger/src/utilities/util_load_json.c @@ -26,589 +26,558 @@ * The raw key/value string is collected in the kvraw field. */ typedef struct { - WT_SESSION *session; /* associated session */ - ULINE line; /* current line */ - const char *p; /* points to cur position in line.mem */ - bool ateof; /* current token is EOF */ - bool peeking; /* peeking at next token */ - int toktype; /* next token, defined by __wt_json_token() */ - const char *tokstart; /* next token start (points into line.mem) */ - size_t toklen; /* next token length */ - char *kvraw; /* multiple line raw content collected so far */ - size_t kvrawstart; /* pos on cur line that JSON key/value starts */ - const char *filename; /* filename for error reporting */ - int linenum; /* line number for error reporting */ + WT_SESSION *session; /* associated session */ + ULINE line; /* current line */ + const char *p; /* points to cur position in line.mem */ + bool ateof; /* current token is EOF */ + bool peeking; /* peeking at next token */ + int toktype; /* next token, defined by __wt_json_token() */ + const char *tokstart; /* next token start (points into line.mem) */ + size_t toklen; /* next token length */ + char *kvraw; /* multiple line raw content collected so far */ + size_t kvrawstart; /* pos on cur line that JSON key/value starts */ + const char *filename; /* filename for error reporting */ + int linenum; /* line number for error reporting */ } JSON_INPUT_STATE; -static int json_column_group_index(WT_SESSION *, JSON_INPUT_STATE *, - CONFIG_LIST *, int); +static int json_column_group_index(WT_SESSION *, JSON_INPUT_STATE *, CONFIG_LIST *, int); static int json_data(WT_SESSION *, JSON_INPUT_STATE *, CONFIG_LIST *, uint32_t); static int json_expect(WT_SESSION *, JSON_INPUT_STATE *, int); static int json_peek(WT_SESSION *, JSON_INPUT_STATE *); static int json_skip(WT_SESSION *, JSON_INPUT_STATE *, const char **); -static int json_kvraw_append( - WT_SESSION *, JSON_INPUT_STATE *, const char *, size_t); +static int json_kvraw_append(WT_SESSION *, JSON_INPUT_STATE *, const char *, size_t); static int json_strdup(WT_SESSION *, JSON_INPUT_STATE *, char **); static int json_top_level(WT_SESSION *, JSON_INPUT_STATE *, uint32_t); -#define JSON_STRING_MATCH(ins, match) \ - ((ins)->toklen - 2 == strlen(match) && \ - strncmp((ins)->tokstart + 1, (match), (ins)->toklen - 2) == 0) +#define JSON_STRING_MATCH(ins, match) \ + ((ins)->toklen - 2 == strlen(match) && \ + strncmp((ins)->tokstart + 1, (match), (ins)->toklen - 2) == 0) -#define JSON_INPUT_POS(ins) \ - ((size_t)((ins)->p - (const char *)(ins)->line.mem)) +#define JSON_INPUT_POS(ins) ((size_t)((ins)->p - (const char *)(ins)->line.mem)) -#define JSON_EXPECT(session, ins, tok) do { \ - if (json_expect(session, ins, tok)) \ - goto err; \ -} while (0) +#define JSON_EXPECT(session, ins, tok) \ + do { \ + if (json_expect(session, ins, tok)) \ + goto err; \ + } while (0) /* * json_column_group_index -- - * Parse a column group or index entry from JSON input. + * Parse a column group or index entry from JSON input. */ static int -json_column_group_index(WT_SESSION *session, - JSON_INPUT_STATE *ins, CONFIG_LIST *clp, int idx) +json_column_group_index(WT_SESSION *session, JSON_INPUT_STATE *ins, CONFIG_LIST *clp, int idx) { - WT_DECL_RET; - char *config, *p, *uri; - bool isconfig; - - uri = NULL; - config = NULL; - - while (json_peek(session, ins) == '{') { - JSON_EXPECT(session, ins, '{'); - JSON_EXPECT(session, ins, 's'); - isconfig = JSON_STRING_MATCH(ins, "config"); - if (!isconfig && !JSON_STRING_MATCH(ins, "uri")) - goto err; - JSON_EXPECT(session, ins, ':'); - JSON_EXPECT(session, ins, 's'); - - if ((ret = json_strdup(session, ins, &p)) != 0) { - ret = util_err(session, ret, NULL); - goto err; - } - if (isconfig) - config = p; - else - uri = p; - - isconfig = !isconfig; - JSON_EXPECT(session, ins, ','); - JSON_EXPECT(session, ins, 's'); - if (!JSON_STRING_MATCH(ins, isconfig ? "config" : "uri")) - goto err; - JSON_EXPECT(session, ins, ':'); - JSON_EXPECT(session, ins, 's'); - - if ((ret = json_strdup(session, ins, &p)) != 0) { - ret = util_err(session, ret, NULL); - goto err; - } - if (isconfig) - config = p; - else - uri = p; - JSON_EXPECT(session, ins, '}'); - if ((idx && strncmp(uri, "index:", 6) != 0) || - (!idx && strncmp(uri, "colgroup:", 9) != 0)) { - ret = util_err(session, EINVAL, - "%s: misplaced colgroup or index", uri); - goto err; - } - if ((ret = config_list_add(session, clp, uri)) != 0 || - (ret = config_list_add(session, clp, config)) != 0) - goto err; - - if (json_peek(session, ins) != ',') - break; - JSON_EXPECT(session, ins, ','); - if (json_peek(session, ins) != '{') - goto err; - } - if (0) { -err: if (ret == 0) - ret = EINVAL; - } - return (ret); + WT_DECL_RET; + char *config, *p, *uri; + bool isconfig; + + uri = NULL; + config = NULL; + + while (json_peek(session, ins) == '{') { + JSON_EXPECT(session, ins, '{'); + JSON_EXPECT(session, ins, 's'); + isconfig = JSON_STRING_MATCH(ins, "config"); + if (!isconfig && !JSON_STRING_MATCH(ins, "uri")) + goto err; + JSON_EXPECT(session, ins, ':'); + JSON_EXPECT(session, ins, 's'); + + if ((ret = json_strdup(session, ins, &p)) != 0) { + ret = util_err(session, ret, NULL); + goto err; + } + if (isconfig) + config = p; + else + uri = p; + + isconfig = !isconfig; + JSON_EXPECT(session, ins, ','); + JSON_EXPECT(session, ins, 's'); + if (!JSON_STRING_MATCH(ins, isconfig ? "config" : "uri")) + goto err; + JSON_EXPECT(session, ins, ':'); + JSON_EXPECT(session, ins, 's'); + + if ((ret = json_strdup(session, ins, &p)) != 0) { + ret = util_err(session, ret, NULL); + goto err; + } + if (isconfig) + config = p; + else + uri = p; + JSON_EXPECT(session, ins, '}'); + if ((idx && strncmp(uri, "index:", 6) != 0) || + (!idx && strncmp(uri, "colgroup:", 9) != 0)) { + ret = util_err(session, EINVAL, "%s: misplaced colgroup or index", uri); + goto err; + } + if ((ret = config_list_add(session, clp, uri)) != 0 || + (ret = config_list_add(session, clp, config)) != 0) + goto err; + + if (json_peek(session, ins) != ',') + break; + JSON_EXPECT(session, ins, ','); + if (json_peek(session, ins) != '{') + goto err; + } + if (0) { +err: + if (ret == 0) + ret = EINVAL; + } + return (ret); } /* * json_kvraw_append -- - * Append to the kvraw buffer, which is used to collect all the - * raw key/value pairs from JSON input. + * Append to the kvraw buffer, which is used to collect all the raw key/value pairs from JSON + * input. */ static int -json_kvraw_append(WT_SESSION *session, - JSON_INPUT_STATE *ins, const char *str, size_t len) +json_kvraw_append(WT_SESSION *session, JSON_INPUT_STATE *ins, const char *str, size_t len) { - WT_DECL_RET; - size_t needsize; - char *tmp; - - if (len > 0) { - needsize = strlen(ins->kvraw) + len + 2; - if ((tmp = malloc(needsize)) == NULL) - return (util_err(session, errno, NULL)); - WT_ERR(__wt_snprintf( - tmp, needsize, "%s %.*s", ins->kvraw, (int)len, str)); - free(ins->kvraw); - ins->kvraw = tmp; - } - return (0); - -err: free(tmp); - return (util_err(session, ret, NULL)); + WT_DECL_RET; + size_t needsize; + char *tmp; + + if (len > 0) { + needsize = strlen(ins->kvraw) + len + 2; + if ((tmp = malloc(needsize)) == NULL) + return (util_err(session, errno, NULL)); + WT_ERR(__wt_snprintf(tmp, needsize, "%s %.*s", ins->kvraw, (int)len, str)); + free(ins->kvraw); + ins->kvraw = tmp; + } + return (0); + +err: + free(tmp); + return (util_err(session, ret, NULL)); } /* * json_strdup -- - * Return a string, with no escapes or other JSON-isms, from the - * JSON string at the current input position. + * Return a string, with no escapes or other JSON-isms, from the JSON string at the current + * input position. */ static int json_strdup(WT_SESSION *session, JSON_INPUT_STATE *ins, char **resultp) { - WT_DECL_RET; - size_t srclen; - ssize_t resultlen; - char *result, *resultcpy; - const char *src; - - result = NULL; - src = ins->tokstart + 1; /*strip "" from token */ - srclen = ins->toklen - 2; - if ((resultlen = __wt_json_strlen(src, srclen)) < 0) { - ret = util_err(session, EINVAL, "Invalid config string"); - goto err; - } - resultlen += 1; - if ((result = malloc((size_t)resultlen)) == NULL) { - ret = util_err(session, errno, NULL); - goto err; - } - *resultp = result; - resultcpy = result; - if ((ret = __wt_json_strncpy( - session, &resultcpy, (size_t)resultlen, src, srclen)) != 0) { - ret = util_err(session, ret, NULL); - goto err; - } - - if (0) { -err: if (ret == 0) - ret = EINVAL; - free(result); - *resultp = NULL; - } - return (ret); + WT_DECL_RET; + size_t srclen; + ssize_t resultlen; + char *result, *resultcpy; + const char *src; + + result = NULL; + src = ins->tokstart + 1; /*strip "" from token */ + srclen = ins->toklen - 2; + if ((resultlen = __wt_json_strlen(src, srclen)) < 0) { + ret = util_err(session, EINVAL, "Invalid config string"); + goto err; + } + resultlen += 1; + if ((result = malloc((size_t)resultlen)) == NULL) { + ret = util_err(session, errno, NULL); + goto err; + } + *resultp = result; + resultcpy = result; + if ((ret = __wt_json_strncpy(session, &resultcpy, (size_t)resultlen, src, srclen)) != 0) { + ret = util_err(session, ret, NULL); + goto err; + } + + if (0) { +err: + if (ret == 0) + ret = EINVAL; + free(result); + *resultp = NULL; + } + return (ret); } /* * json_data -- - * Parse the data portion of the JSON input, and insert all - * values. + * Parse the data portion of the JSON input, and insert all values. */ static int -json_data(WT_SESSION *session, - JSON_INPUT_STATE *ins, CONFIG_LIST *clp, uint32_t flags) +json_data(WT_SESSION *session, JSON_INPUT_STATE *ins, CONFIG_LIST *clp, uint32_t flags) { - WT_CURSOR *cursor; - WT_DECL_RET; - size_t gotnolen, keystrlen; - uint64_t gotno, recno; - int nfield, nkeys, toktype, tret; - char config[64], *endp, *uri; - const char *keyformat; - bool isrec; - - cursor = NULL; - uri = NULL; - - /* Reorder and check the list. */ - if ((ret = config_reorder(session, clp->list)) != 0) - goto err; - - /* Update config based on command-line configuration. */ - if ((ret = config_update(session, clp->list)) != 0) - goto err; - - /* Create the items collected. */ - if ((ret = config_exec(session, clp->list)) != 0) - goto err; - - uri = clp->list[0]; - if ((ret = __wt_snprintf(config, sizeof(config), - "dump=json%s%s", - LF_ISSET(LOAD_JSON_APPEND) ? ",append" : "", - LF_ISSET(LOAD_JSON_NO_OVERWRITE) ? ",overwrite=false" : "")) != 0) { - ret = util_err(session, ret, NULL); - goto err; - } - if ((ret = session->open_cursor( - session, uri, NULL, config, &cursor)) != 0) { - ret = util_err(session, ret, "%s: session.open_cursor", uri); - goto err; - } - keyformat = cursor->key_format; - isrec = WT_STREQ(keyformat, "r"); - for (nkeys = 0; *keyformat; keyformat++) - if (!__wt_isdigit((u_char)*keyformat)) - nkeys++; - - recno = 0; - while (json_peek(session, ins) == '{') { - nfield = 0; - JSON_EXPECT(session, ins, '{'); - if (ins->kvraw == NULL) { - if ((ins->kvraw = malloc(1)) == NULL) { - ret = util_err(session, errno, NULL); - goto err; - } - } - ins->kvraw[0] = '\0'; - ins->kvrawstart = JSON_INPUT_POS(ins); - keystrlen = 0; - while (json_peek(session, ins) == 's') { - JSON_EXPECT(session, ins, 's'); - JSON_EXPECT(session, ins, ':'); - toktype = json_peek(session, ins); - JSON_EXPECT(session, ins, toktype); - if (isrec && nfield == 0) { - /* Verify the dump has recnos in order. */ - recno++; - gotno = __wt_strtouq(ins->tokstart, &endp, 0); - gotnolen = (size_t)(endp - ins->tokstart); - if (recno != gotno || ins->toklen != gotnolen) { - ret = util_err(session, 0, - "%s: recno out of order", uri); - goto err; - } - } - if (++nfield == nkeys) { - size_t curpos = JSON_INPUT_POS(ins); - if ((ret = json_kvraw_append(session, ins, - (char *)ins->line.mem + ins->kvrawstart, - curpos - ins->kvrawstart)) != 0) - goto err; - ins->kvrawstart = curpos; - keystrlen = strlen(ins->kvraw); - } - if (json_peek(session, ins) != ',') - break; - JSON_EXPECT(session, ins, ','); - if (json_peek(session, ins) != 's') - goto err; - } - if (json_kvraw_append( - session, ins, ins->line.mem, JSON_INPUT_POS(ins))) - goto err; - - ins->kvraw[keystrlen] = '\0'; - if (!LF_ISSET(LOAD_JSON_APPEND)) - cursor->set_key(cursor, ins->kvraw); - /* skip over inserted space and comma */ - cursor->set_value(cursor, &ins->kvraw[keystrlen+2]); - if ((ret = cursor->insert(cursor)) != 0) { - ret = util_err(session, ret, "%s: cursor.insert", uri); - goto err; - } - - JSON_EXPECT(session, ins, '}'); - if (json_peek(session, ins) != ',') - break; - JSON_EXPECT(session, ins, ','); - if (json_peek(session, ins) != '{') - goto err; - } - if (0) { -err: if (ret == 0) - ret = EINVAL; - } - /* - * Technically, we don't have to close the cursor because the session - * handle will do it for us, but I'd like to see the flush to disk and - * the close succeed, it's better to fail early when loading files. - */ - if (cursor != NULL && (tret = cursor->close(cursor)) != 0) { - tret = util_err(session, tret, "%s: cursor.close", uri); - if (ret == 0) - ret = tret; - } - if (ret == 0) - ret = util_flush(session, uri); - return (ret); + WT_CURSOR *cursor; + WT_DECL_RET; + size_t gotnolen, keystrlen; + uint64_t gotno, recno; + int nfield, nkeys, toktype, tret; + char config[64], *endp, *uri; + const char *keyformat; + bool isrec; + + cursor = NULL; + uri = NULL; + + /* Reorder and check the list. */ + if ((ret = config_reorder(session, clp->list)) != 0) + goto err; + + /* Update config based on command-line configuration. */ + if ((ret = config_update(session, clp->list)) != 0) + goto err; + + /* Create the items collected. */ + if ((ret = config_exec(session, clp->list)) != 0) + goto err; + + uri = clp->list[0]; + if ((ret = __wt_snprintf(config, sizeof(config), "dump=json%s%s", + LF_ISSET(LOAD_JSON_APPEND) ? ",append" : "", + LF_ISSET(LOAD_JSON_NO_OVERWRITE) ? ",overwrite=false" : "")) != 0) { + ret = util_err(session, ret, NULL); + goto err; + } + if ((ret = session->open_cursor(session, uri, NULL, config, &cursor)) != 0) { + ret = util_err(session, ret, "%s: session.open_cursor", uri); + goto err; + } + keyformat = cursor->key_format; + isrec = WT_STREQ(keyformat, "r"); + for (nkeys = 0; *keyformat; keyformat++) + if (!__wt_isdigit((u_char)*keyformat)) + nkeys++; + + recno = 0; + while (json_peek(session, ins) == '{') { + nfield = 0; + JSON_EXPECT(session, ins, '{'); + if (ins->kvraw == NULL) { + if ((ins->kvraw = malloc(1)) == NULL) { + ret = util_err(session, errno, NULL); + goto err; + } + } + ins->kvraw[0] = '\0'; + ins->kvrawstart = JSON_INPUT_POS(ins); + keystrlen = 0; + while (json_peek(session, ins) == 's') { + JSON_EXPECT(session, ins, 's'); + JSON_EXPECT(session, ins, ':'); + toktype = json_peek(session, ins); + JSON_EXPECT(session, ins, toktype); + if (isrec && nfield == 0) { + /* Verify the dump has recnos in order. */ + recno++; + gotno = __wt_strtouq(ins->tokstart, &endp, 0); + gotnolen = (size_t)(endp - ins->tokstart); + if (recno != gotno || ins->toklen != gotnolen) { + ret = util_err(session, 0, "%s: recno out of order", uri); + goto err; + } + } + if (++nfield == nkeys) { + size_t curpos = JSON_INPUT_POS(ins); + if ((ret = json_kvraw_append(session, ins, (char *)ins->line.mem + ins->kvrawstart, + curpos - ins->kvrawstart)) != 0) + goto err; + ins->kvrawstart = curpos; + keystrlen = strlen(ins->kvraw); + } + if (json_peek(session, ins) != ',') + break; + JSON_EXPECT(session, ins, ','); + if (json_peek(session, ins) != 's') + goto err; + } + if (json_kvraw_append(session, ins, ins->line.mem, JSON_INPUT_POS(ins))) + goto err; + + ins->kvraw[keystrlen] = '\0'; + if (!LF_ISSET(LOAD_JSON_APPEND)) + cursor->set_key(cursor, ins->kvraw); + /* skip over inserted space and comma */ + cursor->set_value(cursor, &ins->kvraw[keystrlen + 2]); + if ((ret = cursor->insert(cursor)) != 0) { + ret = util_err(session, ret, "%s: cursor.insert", uri); + goto err; + } + + JSON_EXPECT(session, ins, '}'); + if (json_peek(session, ins) != ',') + break; + JSON_EXPECT(session, ins, ','); + if (json_peek(session, ins) != '{') + goto err; + } + if (0) { +err: + if (ret == 0) + ret = EINVAL; + } + /* + * Technically, we don't have to close the cursor because the session handle will do it for us, + * but I'd like to see the flush to disk and the close succeed, it's better to fail early when + * loading files. + */ + if (cursor != NULL && (tret = cursor->close(cursor)) != 0) { + tret = util_err(session, tret, "%s: cursor.close", uri); + if (ret == 0) + ret = tret; + } + if (ret == 0) + ret = util_flush(session, uri); + return (ret); } /* * json_top_level -- - * Parse the top level JSON input. + * Parse the top level JSON input. */ static int json_top_level(WT_SESSION *session, JSON_INPUT_STATE *ins, uint32_t flags) { - CONFIG_LIST cl; - WT_DECL_RET; - static const char *json_markers[] = { - "\"config\"", "\"colgroups\"", "\"indices\"", "\"data\"", NULL }; - uint64_t curversion; - int toktype; - char *config, *tableuri; - bool hasversion; - - memset(&cl, 0, sizeof(cl)); - tableuri = NULL; - hasversion = false; - - JSON_EXPECT(session, ins, '{'); - while (json_peek(session, ins) == 's') { - JSON_EXPECT(session, ins, 's'); - tableuri = realloc(tableuri, ins->toklen); - if ((ret = __wt_snprintf(tableuri, ins->toklen, - "%.*s", (int)(ins->toklen - 2), ins->tokstart + 1)) != 0) { - ret = util_err(session, ret, NULL); - goto err; - } - JSON_EXPECT(session, ins, ':'); - if (!hasversion) { - if (strcmp(tableuri, DUMP_JSON_VERSION_MARKER) != 0) { - ret = util_err(session, ENOTSUP, - "missing \"%s\"", DUMP_JSON_VERSION_MARKER); - goto err; - } - hasversion = true; - JSON_EXPECT(session, ins, 's'); - if ((ret = util_str2num(session, - ins->tokstart + 1, false, &curversion)) != 0) - goto err; - if (curversion > DUMP_JSON_SUPPORTED_VERSION) { - ret = util_err(session, ENOTSUP, - "unsupported JSON dump version \"%.*s\"", - (int)(ins->toklen - 1), ins->tokstart + 1); - goto err; - } - JSON_EXPECT(session, ins, ','); - continue; - } - - /* - * Allow any ordering of 'config', 'colgroups', - * 'indices' before 'data', which must appear last. - * The non-'data' items build up a list of entries - * that created in our session before the data is - * inserted. - */ - for (;;) { - if (json_skip(session, ins, json_markers) != 0) - goto err; - JSON_EXPECT(session, ins, 's'); - if (JSON_STRING_MATCH(ins, "config")) { - JSON_EXPECT(session, ins, ':'); - JSON_EXPECT(session, ins, 's'); - if ((ret = - json_strdup(session, ins, &config)) != 0) { - ret = util_err(session, ret, NULL); - goto err; - } - if ((ret = config_list_add( - session, &cl, tableuri)) != 0) - goto err; - if ((ret = config_list_add( - session, &cl, config)) != 0) - goto err; - tableuri = NULL; - } else if (JSON_STRING_MATCH(ins, "colgroups")) { - JSON_EXPECT(session, ins, ':'); - JSON_EXPECT(session, ins, '['); - if ((ret = json_column_group_index( - session, ins, &cl, 0)) != 0) - goto err; - JSON_EXPECT(session, ins, ']'); - } else if (JSON_STRING_MATCH(ins, "indices")) { - JSON_EXPECT(session, ins, ':'); - JSON_EXPECT(session, ins, '['); - if ((ret = json_column_group_index( - session, ins, &cl, 1)) != 0) - goto err; - JSON_EXPECT(session, ins, ']'); - } else if (JSON_STRING_MATCH(ins, "data")) { - JSON_EXPECT(session, ins, ':'); - JSON_EXPECT(session, ins, '['); - if ((ret = json_data(session, ins, &cl, - flags)) != 0) - goto err; - config_list_free(&cl); - free(ins->kvraw); - ins->kvraw = NULL; - config_list_free(&cl); - break; - } - else - goto err; - } - - while ((toktype = json_peek(session, ins)) == '}' || - toktype == ']') - JSON_EXPECT(session, ins, toktype); - if (toktype == 0) /* Check EOF. */ - break; - if (toktype == ',') { - JSON_EXPECT(session, ins, ','); - if (json_peek(session, ins) != 's') - goto err; - continue; - } - } - JSON_EXPECT(session, ins, 0); - - if (0) { -err: if (ret == 0) - ret = EINVAL; - } - config_list_free(&cl); - free(tableuri); - return (ret); + CONFIG_LIST cl; + WT_DECL_RET; + static const char *json_markers[] = { + "\"config\"", "\"colgroups\"", "\"indices\"", "\"data\"", NULL}; + uint64_t curversion; + int toktype; + char *config, *tableuri; + bool hasversion; + + memset(&cl, 0, sizeof(cl)); + tableuri = NULL; + hasversion = false; + + JSON_EXPECT(session, ins, '{'); + while (json_peek(session, ins) == 's') { + JSON_EXPECT(session, ins, 's'); + tableuri = realloc(tableuri, ins->toklen); + if ((ret = __wt_snprintf( + tableuri, ins->toklen, "%.*s", (int)(ins->toklen - 2), ins->tokstart + 1)) != 0) { + ret = util_err(session, ret, NULL); + goto err; + } + JSON_EXPECT(session, ins, ':'); + if (!hasversion) { + if (strcmp(tableuri, DUMP_JSON_VERSION_MARKER) != 0) { + ret = util_err(session, ENOTSUP, "missing \"%s\"", DUMP_JSON_VERSION_MARKER); + goto err; + } + hasversion = true; + JSON_EXPECT(session, ins, 's'); + if ((ret = util_str2num(session, ins->tokstart + 1, false, &curversion)) != 0) + goto err; + if (curversion > DUMP_JSON_SUPPORTED_VERSION) { + ret = util_err(session, ENOTSUP, "unsupported JSON dump version \"%.*s\"", + (int)(ins->toklen - 1), ins->tokstart + 1); + goto err; + } + JSON_EXPECT(session, ins, ','); + continue; + } + + /* + * Allow any ordering of 'config', 'colgroups', + * 'indices' before 'data', which must appear last. + * The non-'data' items build up a list of entries + * that created in our session before the data is + * inserted. + */ + for (;;) { + if (json_skip(session, ins, json_markers) != 0) + goto err; + JSON_EXPECT(session, ins, 's'); + if (JSON_STRING_MATCH(ins, "config")) { + JSON_EXPECT(session, ins, ':'); + JSON_EXPECT(session, ins, 's'); + if ((ret = json_strdup(session, ins, &config)) != 0) { + ret = util_err(session, ret, NULL); + goto err; + } + if ((ret = config_list_add(session, &cl, tableuri)) != 0) + goto err; + if ((ret = config_list_add(session, &cl, config)) != 0) + goto err; + tableuri = NULL; + } else if (JSON_STRING_MATCH(ins, "colgroups")) { + JSON_EXPECT(session, ins, ':'); + JSON_EXPECT(session, ins, '['); + if ((ret = json_column_group_index(session, ins, &cl, 0)) != 0) + goto err; + JSON_EXPECT(session, ins, ']'); + } else if (JSON_STRING_MATCH(ins, "indices")) { + JSON_EXPECT(session, ins, ':'); + JSON_EXPECT(session, ins, '['); + if ((ret = json_column_group_index(session, ins, &cl, 1)) != 0) + goto err; + JSON_EXPECT(session, ins, ']'); + } else if (JSON_STRING_MATCH(ins, "data")) { + JSON_EXPECT(session, ins, ':'); + JSON_EXPECT(session, ins, '['); + if ((ret = json_data(session, ins, &cl, flags)) != 0) + goto err; + config_list_free(&cl); + free(ins->kvraw); + ins->kvraw = NULL; + config_list_free(&cl); + break; + } else + goto err; + } + + while ((toktype = json_peek(session, ins)) == '}' || toktype == ']') + JSON_EXPECT(session, ins, toktype); + if (toktype == 0) /* Check EOF. */ + break; + if (toktype == ',') { + JSON_EXPECT(session, ins, ','); + if (json_peek(session, ins) != 's') + goto err; + continue; + } + } + JSON_EXPECT(session, ins, 0); + + if (0) { +err: + if (ret == 0) + ret = EINVAL; + } + config_list_free(&cl); + free(tableuri); + return (ret); } /* * json_peek -- - * Set the input state to the next available token in the input - * and return its token type, a code defined by __wt_json_token(). + * Set the input state to the next available token in the input and return its token type, a + * code defined by __wt_json_token(). */ static int json_peek(WT_SESSION *session, JSON_INPUT_STATE *ins) { - WT_DECL_RET; - - if (!ins->peeking) { - while (!ins->ateof) { - while (__wt_isspace((u_char)*ins->p)) - ins->p++; - if (*ins->p) - break; - if (ins->kvraw != NULL) { - if (json_kvraw_append(session, ins, - (char *)ins->line.mem + ins->kvrawstart, - strlen(ins->line.mem) - ins->kvrawstart)) { - ret = -1; - goto err; - } - ins->kvrawstart = 0; - } - if (util_read_line( - session, &ins->line, true, &ins->ateof)) { - ins->toktype = -1; - ret = -1; - goto err; - } - ins->linenum++; - ins->p = (const char *)ins->line.mem; - } - if (ins->ateof) - ins->toktype = 0; - else if (__wt_json_token(session, ins->p, - &ins->toktype, &ins->tokstart, - &ins->toklen) != 0) - ins->toktype = -1; - ins->peeking = true; - } - if (0) { - err: if (ret == 0) - ret = -1; - } - return (ret == 0 ? ins->toktype : -1); + WT_DECL_RET; + + if (!ins->peeking) { + while (!ins->ateof) { + while (__wt_isspace((u_char)*ins->p)) + ins->p++; + if (*ins->p) + break; + if (ins->kvraw != NULL) { + if (json_kvraw_append(session, ins, (char *)ins->line.mem + ins->kvrawstart, + strlen(ins->line.mem) - ins->kvrawstart)) { + ret = -1; + goto err; + } + ins->kvrawstart = 0; + } + if (util_read_line(session, &ins->line, true, &ins->ateof)) { + ins->toktype = -1; + ret = -1; + goto err; + } + ins->linenum++; + ins->p = (const char *)ins->line.mem; + } + if (ins->ateof) + ins->toktype = 0; + else if (__wt_json_token(session, ins->p, &ins->toktype, &ins->tokstart, &ins->toklen) != 0) + ins->toktype = -1; + ins->peeking = true; + } + if (0) { +err: + if (ret == 0) + ret = -1; + } + return (ret == 0 ? ins->toktype : -1); } /* * json_expect -- - * Ensure that the type of the next token in the input matches - * the wanted value, and advance past it. The values of the - * input state will be set so specific string or integer values - * can be pulled out after this call. + * Ensure that the type of the next token in the input matches the wanted value, and advance + * past it. The values of the input state will be set so specific string or integer values can + * be pulled out after this call. */ static int json_expect(WT_SESSION *session, JSON_INPUT_STATE *ins, int wanttok) { - if (json_peek(session, ins) < 0) - return (1); - ins->p += ins->toklen; - ins->peeking = false; - if (ins->toktype != wanttok) { - fprintf(stderr, - "%s: %d: %" WT_SIZET_FMT ": expected %s, got %s\n", - ins->filename, - ins->linenum, - JSON_INPUT_POS(ins) + 1, - __wt_json_tokname(wanttok), - __wt_json_tokname(ins->toktype)); - return (1); - } - return (0); + if (json_peek(session, ins) < 0) + return (1); + ins->p += ins->toklen; + ins->peeking = false; + if (ins->toktype != wanttok) { + fprintf(stderr, "%s: %d: %" WT_SIZET_FMT ": expected %s, got %s\n", ins->filename, + ins->linenum, JSON_INPUT_POS(ins) + 1, __wt_json_tokname(wanttok), + __wt_json_tokname(ins->toktype)); + return (1); + } + return (0); } /* * json_skip -- - * Skip over JSON input until one of the specified strings appears. - * The tokenizer will be set to point to the beginning of - * that string. + * Skip over JSON input until one of the specified strings appears. The tokenizer will be set to + * point to the beginning of that string. */ static int json_skip(WT_SESSION *session, JSON_INPUT_STATE *ins, const char **matches) { - const char *hit; - const char **match; - - WT_ASSERT((WT_SESSION_IMPL *)session, ins->kvraw == NULL); - hit = NULL; - while (!ins->ateof) { - for (match = matches; *match != NULL; match++) - if ((hit = strstr(ins->p, *match)) != NULL) - goto out; - if (util_read_line(session, &ins->line, true, &ins->ateof) - != 0) { - ins->toktype = -1; - return (1); - } - ins->linenum++; - ins->p = (const char *)ins->line.mem; - } + const char *hit; + const char **match; + + WT_ASSERT((WT_SESSION_IMPL *)session, ins->kvraw == NULL); + hit = NULL; + while (!ins->ateof) { + for (match = matches; *match != NULL; match++) + if ((hit = strstr(ins->p, *match)) != NULL) + goto out; + if (util_read_line(session, &ins->line, true, &ins->ateof) != 0) { + ins->toktype = -1; + return (1); + } + ins->linenum++; + ins->p = (const char *)ins->line.mem; + } out: - if (hit == NULL) - return (1); - - /* Set to this token. */ - ins->p = hit; - ins->peeking = false; - ins->toktype = 0; - (void)json_peek(session, ins); - return (0); + if (hit == NULL) + return (1); + + /* Set to this token. */ + ins->p = hit; + ins->peeking = false; + ins->toktype = 0; + (void)json_peek(session, ins); + return (0); } /* * load_json -- - * Load from the JSON format produced by 'wt dump -j'. + * Load from the JSON format produced by 'wt dump -j'. */ int util_load_json(WT_SESSION *session, const char *filename, uint32_t flags) { - JSON_INPUT_STATE instate; - WT_DECL_RET; - - memset(&instate, 0, sizeof(instate)); - instate.session = session; - if ((ret = util_read_line( - session, &instate.line, false, &instate.ateof)) == 0) { - instate.p = (const char *)instate.line.mem; - instate.linenum = 1; - instate.filename = filename; - - ret = json_top_level(session, &instate, flags); - } - - free(instate.line.mem); - free(instate.kvraw); - return (ret); + JSON_INPUT_STATE instate; + WT_DECL_RET; + + memset(&instate, 0, sizeof(instate)); + instate.session = session; + if ((ret = util_read_line(session, &instate.line, false, &instate.ateof)) == 0) { + instate.p = (const char *)instate.line.mem; + instate.linenum = 1; + instate.filename = filename; + + ret = json_top_level(session, &instate, flags); + } + + free(instate.line.mem); + free(instate.kvraw); + return (ret); } |