/
sqlite3dbcontext.pmc
130 lines (110 loc) · 4.52 KB
/
sqlite3dbcontext.pmc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "ps_sqlite3.h"
#define GET_DB(s) ((sqlite3*)PARROT_SQLITE3DBCONTEXT(s)->db)
static int
ps_sqlite_callback(void *_rawcbargs, int argc, char **argv, char **azColName)
{
SQLite3_cb_args * const args = (SQLite3_cb_args*)_rawcbargs;
PMC * const self = args->self;
PMC * const table = args->table;
Interp * const interp = args->interp;
INTVAL idx;
PMC * const row = Parrot_pmc_new_init(interp, SQLite3DataRow_type, table);
VTABLE_set_integer_native(interp, row, args->row_idx);
args->row_idx++;
if (!args->have_colnames) {
Hash * const colnames = Parrot_hash_create_sized(interp, enum_hash_int, Hash_key_type_STRING, argc);
for (idx = 0 ; idx < argc; idx++) {
STRING * const colnamestr = Parrot_str_new(interp, azColName[idx], 0);
Parrot_hash_put(interp, colnames, (void*)colnamestr, (void*)idx);
}
VTABLE_set_pointer(interp, table, (void*)colnames);
args->have_colnames = 1;
}
for (idx = 0; idx < argc; idx++) {
// TODO: Double-check encoding, we might need to assume this is binary
STRING * const value = Parrot_str_new(interp, argv[idx], 0);
VTABLE_set_string_keyed_int(interp, row, idx, value);
}
VTABLE_push_pmc(interp, table, row);
}
static PMC *
ps_sqlite_execute_query(PARROT_INTERP, PMC * self, STRING *query)
{
SQLite3_cb_args * args;
sqlite3 * const db = GET_DB(self);
PMC * const table = Parrot_pmc_new(interp, SQLite3DataTable_type);
int rc;
char * err_msg = NULL;
ALLOC_CB_ARGS(args, interp, self, table);
STRING_TO_CSTRING(interp, query, cquery,
rc = sqlite3_exec(db, cquery, ps_sqlite_callback, args, &err_msg);
);
if (rc != SQLITE_OK) {
STRING * const err_str = Parrot_str_new(interp, err_msg, 0);
sqlite3_free(err_msg);
Parrot_ex_throw_from_c_args(interp, NULL, 0, "SQLite Error during db open: %Ss", err_msg);
}
FREE_CB_ARGS(args);
return table;
}
pmclass SQLite3DbContext dynpmc auto_attrs {
ATTR void *db;
VTABLE void init() {
PARROT_SQLITE3DBCONTEXT(SELF)->db = NULL;
PObj_custom_destroy_SET(SELF);
}
VTABLE void destroy() {
sqlite3 * const db = GET_DB(SELF);
if (db)
sqlite3_close(db);
}
METHOD open(STRING *file)
{
sqlite3 * db;
int rc = 0;
STRING_TO_CSTRING(INTERP, file, cfile,
rc = sqlite3_open(cfile, &db);
);
if (rc)
Parrot_ex_throw_from_c_args(INTERP, NULL, 0, "SQLite Error during db open: %s", sqlite3_errmsg(db));
PARROT_SQLITE3DBCONTEXT(SELF)->db = db;
}
METHOD query(STRING * query) {
STRING * const semicolon = Parrot_str_new(INTERP, ";", 0);
if (Parrot_str_find_index(INTERP, query, semicolon, 0) != -1) {
PMC * const queries = Parrot_str_split(INTERP, semicolon, query);
INTVAL num_queries = VTABLE_elements(INTERP, queries);
PMC * const set = Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
INTVAL i;
for (i = 0; i < num_queries; i++) {
STRING * const query = VTABLE_get_string_keyed_int(INTERP, queries, i);
INTVAL const query_length = Parrot_str_length(INTERP, query);
// If the query is empty or is all whitespace, don't bother.
INTVAL const first_non_whitespace = Parrot_str_find_not_cclass(INTERP, enum_cclass_whitespace, query, 0, query_length);
fprintf(stderr, "First not whitespace: %d (%d)\n", first_non_whitespace, query_length);
if (first_non_whitespace < query_length) {
fprintf(stderr, "Performing query\n");
PMC * const table = ps_sqlite_execute_query(INTERP, SELF, query);
VTABLE_push_pmc(INTERP, set, table);
}
}
// If we only have one query, just return that one table.
fprintf(stderr, "tables in set: %d\n", VTABLE_elements(INTERP, set));
if (VTABLE_elements(INTERP, set) == 1) {
PMC * const table = VTABLE_get_pmc_keyed_int(INTERP, set, 0);
RETURN(PMC * table);
}
// If we have zero or more than one, return the whole set.
RETURN(PMC * set);
} else {
PMC * const table = ps_sqlite_execute_query(INTERP, SELF, query);
RETURN(PMC * table);
}
}
METHOD close()
{
sqlite3 * const db = GET_DB(SELF);
if (db)
sqlite3_close(db);
}
}