1 #define UNICODE
2 #define PY_SSIZE_T_CLEAN
3 #include <Python.h>
4
5
6 #include <stdlib.h>
7
8 #include <sqlite3ext.h>
9 SQLITE_EXTENSION_INIT1
10
11 #ifdef _MSC_VER
12 #define MYEXPORT __declspec(dllexport)
13 #else
14 #define MYEXPORT __attribute__ ((visibility ("default")))
15 #endif
16
17 // sortconcat {{{
18
19 typedef struct {
20 unsigned char *val;
21 int index;
22 int length;
23 } SortConcatItem;
24
25 typedef struct {
26 SortConcatItem **vals;
27 int count;
28 int length;
29 } SortConcatList;
30
sort_concat_step(sqlite3_context * context,int argc,sqlite3_value ** argv)31 static void sort_concat_step(sqlite3_context *context, int argc, sqlite3_value **argv) {
32 const unsigned char *val;
33 int idx, sz;
34 SortConcatList *list;
35
36 assert(argc == 2);
37
38 list = (SortConcatList*) sqlite3_aggregate_context(context, sizeof(*list));
39 if (list == NULL) return;
40
41 if (list->vals == NULL) {
42 list->vals = (SortConcatItem**)calloc(100, sizeof(SortConcatItem*));
43 if (list->vals == NULL) return;
44 list->length = 100;
45 list->count = 0;
46 }
47
48 if (list->count == list->length) {
49 list->vals = (SortConcatItem**)realloc(list->vals, sizeof(SortConcatItem*)*(list->length + 100));
50 if (list->vals == NULL) return;
51 list->length = list->length + 100;
52 }
53
54 list->vals[list->count] = (SortConcatItem*)calloc(1, sizeof(SortConcatItem));
55 if (list->vals[list->count] == NULL) return;
56
57 idx = sqlite3_value_int(argv[0]);
58 val = sqlite3_value_text(argv[1]);
59 sz = sqlite3_value_bytes(argv[1]);
60 if (idx == 0 || val == NULL || sz == 0) {free(list->vals[list->count]); return;}
61
62
63
64 list->vals[list->count]->val = (unsigned char*)calloc(sz, sizeof(unsigned char));
65 if (list->vals[list->count]->val == NULL)
66 {free(list->vals[list->count]); return;}
67 list->vals[list->count]->index = idx;
68 list->vals[list->count]->length = sz;
69 memcpy(list->vals[list->count]->val, val, sz);
70 list->count = list->count + 1;
71
72 }
73
sort_concat_free(SortConcatList * list)74 static void sort_concat_free(SortConcatList *list) {
75 int i;
76 if (list == NULL) return;
77 for (i = 0; i < list->count; i++) {
78 free(list->vals[i]->val);
79 free(list->vals[i]);
80 }
81 free(list->vals);
82 }
83
sort_concat_cmp(const void * a_,const void * b_)84 static int sort_concat_cmp(const void *a_, const void *b_) {
85 return (*((SortConcatItem**)a_))->index - (*((SortConcatItem**)b_))->index;
86 }
87
sort_concat_do_finalize(SortConcatList * list,const unsigned char join)88 static unsigned char* sort_concat_do_finalize(SortConcatList *list, const unsigned char join) {
89 unsigned char *ans, *pos;
90 unsigned int sz = 0, i;
91
92 for (i = 0; i < list->count; i++) {
93 sz += list->vals[i]->length;
94 }
95 sz += list->count;
96
97 ans = (unsigned char *) calloc(sz, sizeof(unsigned char));
98 if (ans == NULL) return ans;
99
100 pos = ans;
101 for (i = 0; i < list->count; i++) {
102 if (list->vals[i]->length > 0) {
103 memcpy(pos, list->vals[i]->val, list->vals[i]->length);
104 pos += list->vals[i]->length;
105 if (i < list->count -1) { *pos = join; pos += 1; }
106 }
107 }
108
109 return ans;
110
111 }
112
sort_concat_finalize(sqlite3_context * context)113 static void sort_concat_finalize(sqlite3_context *context) {
114 SortConcatList *list;
115 unsigned char *ans;
116
117 list = (SortConcatList*) sqlite3_aggregate_context(context, sizeof(*list));
118
119 if (list != NULL && list->vals != NULL && list->count > 0) {
120 qsort(list->vals, list->count, sizeof(list->vals[0]), sort_concat_cmp);
121 ans = sort_concat_do_finalize(list, ',');
122 if (ans != NULL) sqlite3_result_text(context, (char*)ans, -1, SQLITE_TRANSIENT);
123 free(ans);
124 sort_concat_free(list);
125 }
126 }
127
sort_concat_finalize2(sqlite3_context * context)128 static void sort_concat_finalize2(sqlite3_context *context) {
129 SortConcatList *list;
130 unsigned char *ans;
131
132 list = (SortConcatList*) sqlite3_aggregate_context(context, sizeof(*list));
133
134 if (list != NULL && list->vals != NULL && list->count > 0) {
135 qsort(list->vals, list->count, sizeof(list->vals[0]), sort_concat_cmp);
136 ans = sort_concat_do_finalize(list, '|');
137 if (ans != NULL) sqlite3_result_text(context, (char*)ans, -1, SQLITE_TRANSIENT);
138 free(ans);
139 sort_concat_free(list);
140 }
141
142 }
143
sort_concat_finalize3(sqlite3_context * context)144 static void sort_concat_finalize3(sqlite3_context *context) {
145 SortConcatList *list;
146 unsigned char *ans;
147
148 list = (SortConcatList*) sqlite3_aggregate_context(context, sizeof(*list));
149
150 if (list != NULL && list->vals != NULL && list->count > 0) {
151 qsort(list->vals, list->count, sizeof(list->vals[0]), sort_concat_cmp);
152 ans = sort_concat_do_finalize(list, '&');
153 if (ans != NULL) sqlite3_result_text(context, (char*)ans, -1, SQLITE_TRANSIENT);
154 free(ans);
155 sort_concat_free(list);
156 }
157
158 }
159
160 // }}}
161
162 // identifiers_concat {{{
163
164 typedef struct {
165 char *val;
166 size_t length;
167 } IdentifiersConcatItem;
168
169 typedef struct {
170 IdentifiersConcatItem **vals;
171 size_t count;
172 size_t length;
173 } IdentifiersConcatList;
174
identifiers_concat_step(sqlite3_context * context,int argc,sqlite3_value ** argv)175 static void identifiers_concat_step(sqlite3_context *context, int argc, sqlite3_value **argv) {
176 const char *key, *val;
177 size_t len = 0;
178 IdentifiersConcatList *list;
179
180 assert(argc == 2);
181
182 list = (IdentifiersConcatList*) sqlite3_aggregate_context(context, sizeof(*list));
183 if (list == NULL) return;
184
185 if (list->vals == NULL) {
186 list->vals = (IdentifiersConcatItem**)calloc(100, sizeof(IdentifiersConcatItem*));
187 if (list->vals == NULL) return;
188 list->length = 100;
189 list->count = 0;
190 }
191
192 if (list->count == list->length) {
193 list->vals = (IdentifiersConcatItem**)realloc(list->vals, sizeof(IdentifiersConcatItem*)*(list->length + 100));
194 if (list->vals == NULL) return;
195 list->length = list->length + 100;
196 }
197
198 list->vals[list->count] = (IdentifiersConcatItem*)calloc(1, sizeof(IdentifiersConcatItem));
199 if (list->vals[list->count] == NULL) return;
200
201 key = (char*) sqlite3_value_text(argv[0]);
202 val = (char*) sqlite3_value_text(argv[1]);
203 if (key == NULL || val == NULL) {return;}
204 len = strlen(key) + strlen(val) + 1;
205
206 list->vals[list->count]->val = (char*)calloc(len+1, sizeof(char));
207 if (list->vals[list->count]->val == NULL) return;
208 snprintf(list->vals[list->count]->val, len+1, "%s:%s", key, val);
209 list->vals[list->count]->length = len;
210
211 list->count = list->count + 1;
212
213 }
214
215
identifiers_concat_finalize(sqlite3_context * context)216 static void identifiers_concat_finalize(sqlite3_context *context) {
217 IdentifiersConcatList *list;
218 IdentifiersConcatItem *item;
219 char *ans, *pos;
220 size_t sz = 0, i;
221
222 list = (IdentifiersConcatList*) sqlite3_aggregate_context(context, sizeof(*list));
223 if (list == NULL || list->vals == NULL || list->count < 1) return;
224
225 for (i = 0; i < list->count; i++) {
226 sz += list->vals[i]->length;
227 }
228 sz += list->count; // Space for commas
229 ans = (char*)calloc(sz+2, sizeof(char));
230 if (ans == NULL) return;
231
232 pos = ans;
233
234 for (i = 0; i < list->count; i++) {
235 item = list->vals[i];
236 if (item == NULL || item->val == NULL) continue;
237 memcpy(pos, item->val, item->length);
238 pos += item->length;
239 *pos = ',';
240 pos += 1;
241 free(item->val);
242 free(item);
243 }
244 *(pos-1) = 0; // Remove trailing comma
245 sqlite3_result_text(context, ans, -1, SQLITE_TRANSIENT);
246 free(ans);
247 free(list->vals);
248 }
249
250 // }}}
251
sqlite3_extension_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)252 MYEXPORT int sqlite3_extension_init(
253 sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi){
254 SQLITE_EXTENSION_INIT2(pApi);
255 sqlite3_create_function(db, "sortconcat", 2, SQLITE_UTF8, NULL, NULL, sort_concat_step, sort_concat_finalize);
256 sqlite3_create_function(db, "sortconcat_bar", 2, SQLITE_UTF8, NULL, NULL, sort_concat_step, sort_concat_finalize2);
257 sqlite3_create_function(db, "sortconcat_amper", 2, SQLITE_UTF8, NULL, NULL, sort_concat_step, sort_concat_finalize3);
258 sqlite3_create_function(db, "identifiers_concat", 2, SQLITE_UTF8, NULL, NULL, identifiers_concat_step, identifiers_concat_finalize);
259 return 0;
260 }
261
262 static PyObject *
sqlite_custom_init_funcs(PyObject * self,PyObject * args)263 sqlite_custom_init_funcs(PyObject *self, PyObject *args) {
264 Py_RETURN_NONE;
265 }
266
267 static char sqlite_custom_doc[] = "Implementation of custom sqlite methods in C for speed.";
268
269 static PyMethodDef sqlite_custom_methods[] = {
270 {"init_funcs", sqlite_custom_init_funcs, METH_VARARGS,
271 "init_funcs()\n\nInitialize module."
272 },
273
274 {NULL, NULL, 0, NULL}
275 };
276
277 static int
exec_module(PyObject * module)278 exec_module(PyObject *module) { return 0; }
279
280 static PyModuleDef_Slot slots[] = { {Py_mod_exec, exec_module}, {0, NULL} };
281
282 static struct PyModuleDef module_def = {
283 .m_base = PyModuleDef_HEAD_INIT,
284 .m_name = "sqlite_custom",
285 .m_doc = sqlite_custom_doc,
286 .m_methods = sqlite_custom_methods,
287 .m_slots = slots,
288 };
289
PyInit_sqlite_custom(void)290 CALIBRE_MODINIT_FUNC PyInit_sqlite_custom(void) { return PyModuleDef_Init(&module_def); }
291