diff --git a/contrib/msggen/msggen/schema.json b/contrib/msggen/msggen/schema.json index 1ffc7fafbf92..f61fdffae3cd 100644 --- a/contrib/msggen/msggen/schema.json +++ b/contrib/msggen/msggen/schema.json @@ -32538,7 +32538,9 @@ "* time", "* timediff", "* total", - "* unixepoch" + "* unixepoch", + "* json_object", + "* json_group_array" ], "tables": [ "Note that the first column of every table is a unique integer called `rowid`: this is used for related tables to refer to specific rows in their parent. sqlite3 usually has this as an implicit column, but we make it explicit as the implicit version is not allowed to be used as a foreign key.", diff --git a/doc/schemas/sql-template.json b/doc/schemas/sql-template.json index eee7f8db06a3..eb3327466228 100644 --- a/doc/schemas/sql-template.json +++ b/doc/schemas/sql-template.json @@ -107,7 +107,9 @@ "* time", "* timediff", "* total", - "* unixepoch" + "* unixepoch", + "* json_object", + "* json_group_array" ], "tables": [ "Note that the first column of every table is a unique integer called `rowid`: this is used for related tables to refer to specific rows in their parent. sqlite3 usually has this as an implicit column, but we make it explicit as the implicit version is not allowed to be used as a foreign key.", diff --git a/plugins/sql.c b/plugins/sql.c index 9e4ca305b4b2..d61452f4b91c 100644 --- a/plugins/sql.c +++ b/plugins/sql.c @@ -352,6 +352,10 @@ static int sqlite_authorize(void *dbq_, int code, return SQLITE_OK; if (streq(b, "unixepoch")) return SQLITE_OK; + if (streq(b, "json_object")) + return SQLITE_OK; + if (streq(b, "json_group_array")) + return SQLITE_OK; } /* See https://www.sqlite.org/c3ref/c_alter_table.html to decode these! */ diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 761d82df2ce4..ece9a020dc66 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -3925,6 +3925,21 @@ def test_sql(node_factory, bitcoind): l2.rpc.connect(l3.info['id'], 'localhost', l3.port) wait_for(lambda: l3.rpc.sql("SELECT * FROM nodes WHERE alias = '{}'".format(alias))['rows'] != []) + # Test json functions + l1.fundchannel(l2) + bitcoind.generate_block(6) + l1.rpc.pay(l2.rpc.invoice(amount_msat=1000000, label='inv1000', description='description 1000 msat')['bolt11']) + ret = l1.rpc.sql("SELECT json_object('peer_id', hex(pc.peer_id), 'alias', alias, 'htlcs'," + " (SELECT json_group_array(json_object('id', hex(id), 'amount_msat', amount_msat))" + " FROM peerchannels_htlcs ph WHERE ph.row = pc.rowid)) FROM peerchannels pc JOIN nodes n" + " ON pc.peer_id = n.nodeid ORDER BY n.alias, pc.peer_id;") + assert len(ret['rows']) == 2 + row1 = json.loads(ret['rows'][0][0]) + row2 = json.loads(ret['rows'][1][0]) + assert row1['peer_id'] == format(l2.info['id'].upper()) + assert len(row2['htlcs']) == 1 + assert row2['htlcs'][0]['amount_msat'] == 1000000 + def test_sql_deprecated(node_factory, bitcoind): l1, l2 = node_factory.line_graph(2, opts=[{'allow-deprecated-apis': True}, {}])