Reuse a Query with a Plan
Every query call compiles its query string, runs it, and throws the compiled form away. A plan keeps it, so a query you run in a loop is compiled once.
In Python
db.prepare hands you back a plan:
>>> db.execute("create out u32")
>>> db.write("insert out 0 4", [1, 2, 3, 4])
4
>>> plan = db.prepare("read out[0:2]")
>>> plan
<Plan 'read out[0:2]'>
>>> plan.read()
array([1, 2], dtype=uint32)
>>> plan.read()
array([1, 2], dtype=uint32)
>>> plan.close()A Plan has the same execute /
read / read_into /
write / var methods, each taking
an optional transaction as its last argument, and it's a
context manager like everything else:
>>> with db.prepare("insert out 0 2") as plan:
... with db.begin() as txn:
... plan.write([10, 20], txn)
2
>>> db.read("read out")
array([10, 20, 1, 2, 3, 4], dtype=uint32)In C
In C, ns_plan_fcreate compiles a plan:
#include "numstore.h"
#include <inttypes.h>
#include <stdio.h>
int
main (void)
{
ns_cleanup ("plans.db");
nsdb_t *db = ns_open ("plans.db");
ns_execute (db, NULL, "create samples u32");
// Compile once.
nsdb_plan_t *append = ns_plan_fcreate (db, "insert samples 0 4");
if (append == NULL) {
fprintf (stderr, "plan failed: %s\n", ns_strerror (db, false));
ns_close (db);
return 1;
}
// Run it many times.
for (int batch = 0; batch < 3; batch++) {
const uint32_t src[] = {1, 2, 3, 4};
sb_size n = ns_plan_write (append, NULL, src, sizeof (src));
if (n < 0) {
fprintf (stderr, "write failed: %s\n", ns_plan_strerror (append, false));
ns_plan_free (append);
ns_close (db);
return 1;
}
printf ("batch %d wrote %" PRId64 "\n", batch, n);
}
nsdb_var_t *var = ns_plan_get_var (append, NULL);
printf ("samples now holds %" PRIu64 " elements\n", ns_var_len (var));
ns_var_free (var);
ns_plan_free (append); // plans must be freed before the database closes
nsdb_plan_t *head = ns_plan_fcreate (db, "read samples[0:4]");
uint32_t out[4];
sb_size n = ns_plan_read (head, NULL, out, sizeof (out));
printf ("first %" PRId64 ":", n);
for (sb_size i = 0; i < n; i++) {
printf (" %u", out[i]);
}
printf ("\n");
ns_plan_free (head);
return ns_close (db);
}batch 0 wrote 4
batch 1 wrote 4
batch 2 wrote 4
samples now holds 12 elements
first 4: 1 2 3 4
Each plan function mirrors the one-shot function, with the transaction as an argument so one compiled plan can run inside any transaction:
| One shot | Prepared |
|---|---|
ns_execute |
ns_plan_execute |
ns_read |
ns_plan_read |
ns_write |
ns_plan_write |
ns_malloc |
ns_plan_malloc |
ns_get_var |
ns_plan_get_var |
ns_strerror |
ns_plan_strerror |
Plans must be freed before the database closes.