Browse Source
This is the counterpart of the annotations we did in the last few commits. It extracts queries, passes them through a driver-specific query rewriter and dumps them into a driver-specific query-list, along with some metadata to facilitate processing later on. The generated query list is then registered as a `db_config` and will be loaded by the driver upon instantiation. Signed-off-by: Christian Decker <decker.christian@gmail.com>pull/2803/head
Christian Decker
6 years ago
committed by
Rusty Russell
11 changed files with 215 additions and 4 deletions
@ -0,0 +1,102 @@ |
|||
#!/usr/bin/env python3 |
|||
|
|||
from mako.template import Template |
|||
|
|||
import sys |
|||
|
|||
|
|||
class Sqlite3Rewriter(object): |
|||
def rewrite(self, query): |
|||
return query |
|||
|
|||
|
|||
rewriters = { |
|||
"sqlite3": Sqlite3Rewriter(), |
|||
} |
|||
|
|||
template = Template("""#ifndef LIGHTNINGD_WALLET_GEN_DB_${f.upper()} |
|||
#define LIGHTNINGD_WALLET_GEN_DB_${f.upper()} |
|||
|
|||
#include <config.h> |
|||
#include <wallet/db_common.h> |
|||
|
|||
#if HAVE_${f.upper()} |
|||
|
|||
struct db_query db_${f}_queries[] = { |
|||
|
|||
% for elem in queries: |
|||
{ |
|||
.name = "${elem['name']}", |
|||
.query = "${elem['query']}", |
|||
.placeholders = ${elem['placeholders']} |
|||
}, |
|||
% endfor |
|||
}; |
|||
|
|||
#define DB_${f.upper()}_QUERY_COUNT ${len(queries)} |
|||
|
|||
#endif /* HAVE_${f.upper()} */ |
|||
|
|||
#endif /* LIGHTNINGD_WALLET_GEN_DB_${f.upper()} */ |
|||
""") |
|||
|
|||
|
|||
def extract_queries(pofile): |
|||
# Given a po-file, extract all queries and their associated names, and |
|||
# return them as a list. |
|||
|
|||
def chunk(pofile): |
|||
# Chunk a given file into chunks separated by an empty line |
|||
with open(pofile, 'r') as f: |
|||
chunk = [] |
|||
for line in f: |
|||
line = line.strip() |
|||
if line.strip() == "": |
|||
yield chunk |
|||
chunk = [] |
|||
else: |
|||
chunk.append(line.strip()) |
|||
if chunk != []: |
|||
yield chunk |
|||
|
|||
queries = [] |
|||
for c in chunk(pofile): |
|||
name = c[0][3:] |
|||
|
|||
# Skip other comments |
|||
i = 1 |
|||
while c[i][0] == '#': |
|||
i += 1 |
|||
|
|||
# Strip header and surrounding quotes |
|||
query = c[i][7:][:-1] |
|||
|
|||
queries.append({ |
|||
'name': name, |
|||
'query': query, |
|||
'placeholders': query.count('?'), |
|||
'readonly': "true" if query.upper().startswith("SELECT") else "false", |
|||
}) |
|||
return queries |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
if len(sys.argv) != 3: |
|||
print("Usage:\n\t{} <statements.po-file> <output-dialect>".format(sys.argv[0])) |
|||
sys.exit(1) |
|||
|
|||
dialect = sys.argv[2] |
|||
|
|||
if dialect not in rewriters: |
|||
print("Unknown dialect {}. The following are available: {}".format( |
|||
dialect, |
|||
", ".join(rewriters.keys()) |
|||
)) |
|||
sys.exit(1) |
|||
|
|||
rewriter = rewriters[dialect] |
|||
|
|||
queries = extract_queries(sys.argv[1]) |
|||
queries = rewriter.rewrite(queries) |
|||
|
|||
print(template.render(f=dialect, queries=queries)) |
@ -0,0 +1,3 @@ |
|||
sqlparse==0.3.0 |
|||
mako==1.0.14 |
|||
mrkd==0.1.5 |
@ -0,0 +1,56 @@ |
|||
#ifndef LIGHTNING_WALLET_DB_COMMON_H |
|||
#define LIGHTNING_WALLET_DB_COMMON_H |
|||
#include "config.h" |
|||
#include <ccan/autodata/autodata.h> |
|||
#include <ccan/short_types/short_types.h> |
|||
|
|||
struct db_query { |
|||
const char *name; |
|||
const char *query; |
|||
|
|||
/* How many placeholders are in the query (and how many will we have
|
|||
to allocate when instantiating this query)? */ |
|||
size_t placeholders; |
|||
}; |
|||
|
|||
struct db_config { |
|||
const char *name; |
|||
struct db_query *queries; |
|||
size_t num_queries; |
|||
}; |
|||
|
|||
enum db_binding_type { |
|||
DB_BINDING_UNINITIALIZED = 0, |
|||
DB_BINDING_NULL, |
|||
DB_BINDING_BLOB, |
|||
DB_BINDING_TEXT, |
|||
DB_BINDING_UINT64, |
|||
DB_BINDING_INT, |
|||
}; |
|||
|
|||
struct db_binding { |
|||
enum db_binding_type type; |
|||
union { |
|||
int i; |
|||
u64 u64; |
|||
const char* text; |
|||
const u8 *blob; |
|||
} v; |
|||
size_t len; |
|||
}; |
|||
|
|||
struct db_stmt { |
|||
/* Which SQL statement are we trying to execute? */ |
|||
struct db_query *query; |
|||
|
|||
/* Which parameters are we binding to the statement? */ |
|||
struct db_binding *bindings; |
|||
|
|||
/* Where are we calling this statement from? */ |
|||
const char *location; |
|||
}; |
|||
|
|||
/* Provide a way for DB backends to register themselves */ |
|||
AUTODATA_TYPE(db_backends, struct db_config); |
|||
|
|||
#endif /* LIGHTNING_WALLET_DB_COMMON_H */ |
@ -0,0 +1,13 @@ |
|||
#include <wallet/db_common.h> |
|||
#include "gen_db_sqlite3.c" |
|||
#if HAVE_SQLITE3 |
|||
|
|||
struct db_config db_sqlite3_config = { |
|||
.name = "sqlite3", |
|||
.queries = db_sqlite3_queries, |
|||
.num_queries = DB_SQLITE3_QUERY_COUNT, |
|||
}; |
|||
|
|||
AUTODATA(db_backends, &db_sqlite3_config); |
|||
|
|||
#endif |
Loading…
Reference in new issue