diff --git a/plugins/sql.c b/plugins/sql.c index 8d3447e4f..f2ef3a8b8 100644 --- a/plugins/sql.c +++ b/plugins/sql.c @@ -23,7 +23,6 @@ static const char schemas[] = * 6. test on mainnet. * 7. Some cool query for documentation. * 8. time_msec fields. - * 9. Primary key in schema? * 10. Pagination API */ enum fieldtype { @@ -109,6 +108,56 @@ static size_t max_dbmem = 500000000; static struct sqlite3 *db; static const char *dbfilename; +/* It was tempting to put these in the schema, but they're really + * just for our usage. Though that would allow us to autogen the + * documentation, too. */ +struct index { + const char *tablename; + const char *fields[2]; +}; +static const struct index indices[] = { + { + "channels", + { "short_channel_id", NULL }, + }, + { + "forwards", + { "in_channel", "in_htlc_id" }, + }, + { + "htlcs", + { "short_channel_id", "id" }, + }, + { + "invoices", + { "payment_hash", NULL }, + }, + { + "nodes", + { "nodeid", NULL }, + }, + { + "offers", + { "offer_id", NULL }, + }, + { + "peers", + { "id", NULL }, + }, + { + "peerchannels", + { "peer_id", NULL }, + }, + { + "sendpays", + { "payment_hash", NULL }, + }, + { + "transactions", + { "hash", NULL }, + }, +}; + static enum fieldtype find_fieldtype(const jsmntok_t *name) { for (size_t i = 0; i < ARRAY_SIZE(fieldtypemap); i++) { @@ -643,7 +692,6 @@ static void finish_td(struct plugin *plugin, struct table_desc *td) if (td->is_subobject) return; - /* FIXME: Primary key from schema? */ create_stmt = tal_fmt(tmpctx, "CREATE TABLE %s (", td->name); td->update_stmt = tal_fmt(td, "INSERT INTO %s VALUES (", td->name); @@ -896,6 +944,25 @@ static void init_tablemap(struct plugin *plugin) } } +static void init_indices(struct plugin *plugin) +{ + for (size_t i = 0; i < ARRAY_SIZE(indices); i++) { + char *errmsg, *cmd; + int err; + + cmd = tal_fmt(tmpctx, "CREATE INDEX %s_%zu_idx ON %s (%s", + indices[i].tablename, i, + indices[i].tablename, + indices[i].fields[0]); + if (indices[i].fields[1]) + tal_append_fmt(&cmd, ", %s", indices[i].fields[1]); + tal_append_fmt(&cmd, ");"); + err = sqlite3_exec(db, cmd, NULL, NULL, &errmsg); + if (err != SQLITE_OK) + plugin_err(plugin, "Failed '%s': %s", cmd, errmsg); + } +} + #if DEVELOPER static void memleak_mark_tablemap(struct plugin *p, struct htable *memtable) { @@ -909,6 +976,7 @@ static const char *init(struct plugin *plugin, { db = sqlite_setup(plugin); init_tablemap(plugin); + init_indices(plugin); #if DEVELOPER plugin_set_memleak_handler(plugin, memleak_mark_tablemap); diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 748f61e5d..75a460e4a 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -3293,6 +3293,7 @@ def test_sql(node_factory, bitcoind): expected_schemas = { 'channels': { + 'indices': [['short_channel_id']], 'columns': [{'name': 'source', 'type': 'pubkey'}, {'name': 'destination', @@ -3326,6 +3327,7 @@ def test_sql(node_factory, bitcoind): {'name': 'features', 'type': 'hex'}]}, 'nodes': { + 'indices': [['nodeid']], 'columns': [{'name': 'nodeid', 'type': 'pubkey'}, {'name': 'last_timestamp', @@ -3361,6 +3363,7 @@ def test_sql(node_factory, bitcoind): {'name': 'address', 'type': 'string'}]}, 'forwards': { + 'indices': [['in_channel', 'in_htlc_id']], 'columns': [{'name': 'in_channel', 'type': 'short_channel_id'}, {'name': 'in_htlc_id', @@ -3388,6 +3391,7 @@ def test_sql(node_factory, bitcoind): {'name': 'failreason', 'type': 'string'}]}, 'htlcs': { + 'indices': [['short_channel_id', 'id']], 'columns': [{'name': 'short_channel_id', 'type': 'short_channel_id'}, {'name': 'id', @@ -3403,6 +3407,7 @@ def test_sql(node_factory, bitcoind): {'name': 'state', 'type': 'string'}]}, 'invoices': { + 'indices': [['payment_hash']], 'columns': [{'name': 'label', 'type': 'string'}, {'name': 'description', @@ -3432,6 +3437,7 @@ def test_sql(node_factory, bitcoind): {'name': 'payment_preimage', 'type': 'secret'}]}, 'offers': { + 'indices': [['offer_id']], 'columns': [{'name': 'offer_id', 'type': 'hex'}, {'name': 'active', @@ -3445,6 +3451,7 @@ def test_sql(node_factory, bitcoind): {'name': 'label', 'type': 'string'}]}, 'peers': { + 'indices': [['id']], 'columns': [{'name': 'id', 'type': 'pubkey'}, {'name': 'connected', @@ -3461,6 +3468,7 @@ def test_sql(node_factory, bitcoind): {'name': 'netaddr', 'type': 'string'}]}, 'sendpays': { + 'indices': [['payment_hash']], 'columns': [{'name': 'id', 'type': 'u64'}, {'name': 'groupid', @@ -3492,6 +3500,7 @@ def test_sql(node_factory, bitcoind): {'name': 'erroronion', 'type': 'hex'}]}, 'peerchannels': { + 'indices': [['peer_id']], 'columns': [{'name': 'peer_id', 'type': 'pubkey'}, {'name': 'peer_connected', @@ -3674,6 +3683,7 @@ def test_sql(node_factory, bitcoind): {'name': 'message', 'type': 'string'}]}, 'transactions': { + 'indices': [['hash']], 'columns': [{'name': 'hash', 'type': 'txid'}, {'name': 'rawtx',