From d818614aa9e67419c03760fa9f05245da255b281 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Mar 2023 10:49:47 +1030 Subject: [PATCH] plugins/sql: recurse correctly into complex objects during processing. We didn't handle the case of an array inside a subobject. But that happens when we add the next commit! Signed-off-by: Rusty Russell --- plugins/sql.c | 61 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/plugins/sql.c b/plugins/sql.c index 60122b021..6c0036859 100644 --- a/plugins/sql.c +++ b/plugins/sql.c @@ -422,6 +422,39 @@ static struct command_result *process_json_list(struct command *cmd, const u64 *rowid, const struct table_desc *td); +/* Process all subobject columns */ +static struct command_result *process_json_subobjs(struct command *cmd, + const char *buf, + const jsmntok_t *t, + const struct table_desc *td, + u64 this_rowid) +{ + for (size_t i = 0; i < tal_count(td->columns); i++) { + const struct column *col = &td->columns[i]; + struct command_result *ret; + const jsmntok_t *coltok; + + if (!col->sub) + continue; + + coltok = json_get_member(buf, t, col->jsonname); + if (!coltok) + continue; + + /* If it's an array, use process_json_list */ + if (!col->sub->is_subobject) { + ret = process_json_list(cmd, buf, coltok, &this_rowid, + col->sub); + } else { + ret = process_json_subobjs(cmd, buf, coltok, col->sub, + this_rowid); + } + if (ret) + return ret; + } + return NULL; +} + /* Returns NULL on success, otherwise has failed cmd. */ static struct command_result *process_json_obj(struct command *cmd, const char *buf, @@ -569,23 +602,7 @@ static struct command_result *process_json_obj(struct command *cmd, sqlite3_errmsg(db)); } - for (size_t i = 0; i < tal_count(td->columns); i++) { - const struct column *col = &td->columns[i]; - const jsmntok_t *coltok; - struct command_result *ret; - - if (!col->sub || col->sub->is_subobject) - continue; - - coltok = json_get_member(buf, t, col->jsonname); - if (!coltok) - continue; - - ret = process_json_list(cmd, buf, coltok, &this_rowid, col->sub); - if (ret) - return ret; - } - return NULL; + return process_json_subobjs(cmd, buf, t, td, this_rowid); } /* A list, such as in the top-level reply, or for a sub-table */ @@ -1150,7 +1167,8 @@ static void finish_td(struct plugin *plugin, struct table_desc *td) /* subobject are separate at JSON level, folded at db level! */ if (td->is_subobject) - return; + /* But it might have sub-sub objects! */ + goto do_subtables; /* We make an explicit rowid in each table, for subtables to access. This is * becuase the implicit rowid can't be used as a foreign key! */ @@ -1160,10 +1178,14 @@ static void finish_td(struct plugin *plugin, struct table_desc *td) /* If we're a child array, we reference the parent column */ if (td->parent) { + /* But if parent is a subobject, we reference the outer! */ + struct table_desc *parent = td->parent; + while (parent->is_subobject) + parent = parent->parent; tal_append_fmt(&create_stmt, "row INTEGER REFERENCES %s(rowid) ON DELETE CASCADE," " arrindex INTEGER", - td->parent->name); + parent->name); tal_append_fmt(&td->update_stmt, "?,?"); sep = ","; } @@ -1190,6 +1212,7 @@ static void finish_td(struct plugin *plugin, struct table_desc *td) if (err != SQLITE_OK) plugin_err(plugin, "Could not create %s: %s", td->name, errmsg); +do_subtables: /* Now do any children */ for (size_t i = 0; i < tal_count(td->columns); i++) { const struct column *col = &td->columns[i];