File Coverage

dbdimp_virtual_table.inc
Criterion Covered Total %
statement 0 443 0.0
branch 0 468 0.0
condition n/a
subroutine n/a
pod n/a
total 0 911 0.0


line stmt bran cond sub pod time code
1             /***********************************************************************
2             ** The set of routines that implement the perl "module"
3             ** (i.e support for virtual tables written in Perl)
4             ************************************************************************/
5              
6             typedef struct perl_vtab {
7             sqlite3_vtab base;
8             SV *perl_vtab_obj;
9             HV *functions;
10             } perl_vtab;
11              
12             typedef struct perl_vtab_cursor {
13             sqlite3_vtab_cursor base;
14             SV *perl_cursor_obj;
15             } perl_vtab_cursor;
16              
17             typedef struct perl_vtab_init {
18             SV *dbh;
19             const char *perl_class;
20             } perl_vtab_init;
21              
22              
23              
24             /* auxiliary routine for generalized method calls. Arg "i" may be unused */
25 0           static int _call_perl_vtab_method(sqlite3_vtab *pVTab,
26             const char *method, int i) {
27             dTHX;
28 0           dSP;
29             int count;
30              
31 0           ENTER;
32 0           SAVETMPS;
33              
34 0 0         PUSHMARK(SP);
35 0 0         XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj);
36 0 0         XPUSHs(sv_2mortal(newSViv(i)));
37 0           PUTBACK;
38 0           count = call_method (method, G_VOID);
39 0           SPAGAIN;
40 0           SP -= count;
41              
42 0           PUTBACK;
43 0 0         FREETMPS;
44 0           LEAVE;
45              
46 0           return SQLITE_OK;
47             }
48              
49              
50              
51 0           static int perl_vt_New(const char *method,
52             sqlite3 *db, void *pAux,
53             int argc, const char *const *argv,
54             sqlite3_vtab **ppVTab, char **pzErr){
55             dTHX;
56 0           dSP;
57             perl_vtab *vt;
58 0           perl_vtab_init *init_data = (perl_vtab_init *)pAux;
59             int count, i;
60 0           int rc = SQLITE_ERROR;
61             SV *perl_vtab_obj;
62             SV *sql;
63              
64             /* allocate a perl_vtab structure */
65 0           vt = (perl_vtab *) sqlite3_malloc(sizeof(*vt));
66 0 0         if( vt==NULL ) return SQLITE_NOMEM;
67 0           memset(vt, 0, sizeof(*vt));
68 0           vt->functions = newHV();
69              
70 0           ENTER;
71 0           SAVETMPS;
72              
73             /* call the ->CREATE/CONNECT() method */
74 0 0         PUSHMARK(SP);
75 0 0         XPUSHs(sv_2mortal(newSVpv(init_data->perl_class, 0)));
76 0 0         XPUSHs(init_data->dbh);
77 0 0         for(i = 0; i < argc; i++) {
78 0 0         XPUSHs(newSVpvn_flags(argv[i], strlen(argv[i]), SVs_TEMP|SVf_UTF8));
79             }
80 0           PUTBACK;
81 0           count = call_method (method, G_SCALAR);
82 0           SPAGAIN;
83              
84             /* check the return value */
85 0 0         if ( count != 1 ) {
86 0           *pzErr = sqlite3_mprintf("vtab->%s() should return one value, got %d",
87             method, count );
88 0           SP -= count; /* Clear the stack */
89 0           goto cleanup;
90             }
91              
92             /* get the VirtualTable instance */
93 0           perl_vtab_obj = POPs;
94 0 0         if ( !sv_isobject(perl_vtab_obj) ) {
95 0           *pzErr = sqlite3_mprintf("vtab->%s() should return a blessed reference",
96             method);
97 0           goto cleanup;
98             }
99              
100             /* call the ->VTAB_TO_DECLARE() method */
101 0 0         PUSHMARK(SP);
102 0 0         XPUSHs(perl_vtab_obj);
103 0           PUTBACK;
104 0           count = call_method ("VTAB_TO_DECLARE", G_SCALAR);
105 0           SPAGAIN;
106              
107             /* check the return value */
108 0 0         if (count != 1 ) {
109 0           *pzErr = sqlite3_mprintf("vtab->VTAB_TO_DECLARE() should return one value, got %d",
110             count );
111 0           SP -= count; /* Clear the stack */
112 0           goto cleanup;
113             }
114              
115             /* call sqlite3_declare_vtab with the sql returned from
116             method VTAB_TO_DECLARE(), converted to utf8 */
117 0           sql = POPs;
118 0 0         rc = sqlite3_declare_vtab(db, SvPVutf8_nolen(sql));
119              
120             cleanup:
121 0 0         if (rc == SQLITE_OK) {
122             /* record the VirtualTable perl instance within the vtab structure */
123 0           vt->perl_vtab_obj = SvREFCNT_inc(perl_vtab_obj);
124 0           *ppVTab = &vt->base;
125             }
126             else {
127 0           sqlite3_free(vt);
128             }
129              
130 0           PUTBACK;
131 0 0         FREETMPS;
132 0           LEAVE;
133              
134 0           return rc;
135             }
136              
137              
138 0           static int perl_vt_Create(sqlite3 *db, void *pAux,
139             int argc, const char *const *argv,
140             sqlite3_vtab **ppVTab, char **pzErr){
141 0           return perl_vt_New("CREATE", db, pAux, argc, argv, ppVTab, pzErr);
142             }
143              
144 0           static int perl_vt_Connect(sqlite3 *db, void *pAux,
145             int argc, const char *const *argv,
146             sqlite3_vtab **ppVTab, char **pzErr){
147 0           return perl_vt_New("CONNECT", db, pAux, argc, argv, ppVTab, pzErr);
148             }
149              
150              
151 0           static int _free_perl_vtab(perl_vtab *pVTab){
152             dTHX;
153              
154 0           SvREFCNT_dec(pVTab->perl_vtab_obj);
155              
156             /* deallocate coderefs that were declared through FindFunction() */
157 0           hv_undef(pVTab->functions);
158 0           SvREFCNT_dec(pVTab->functions);
159              
160 0           sqlite3_free(pVTab);
161 0           return SQLITE_OK;
162             }
163              
164 0           static int perl_vt_Disconnect(sqlite3_vtab *pVTab){
165 0           _call_perl_vtab_method(pVTab, "DISCONNECT", 0);
166 0           return _free_perl_vtab((perl_vtab *)pVTab);
167             }
168              
169 0           static int perl_vt_Drop(sqlite3_vtab *pVTab){
170 0           _call_perl_vtab_method(pVTab, "DROP", 0);
171 0           return _free_perl_vtab((perl_vtab *)pVTab);
172             }
173              
174              
175             static char *
176 0           _constraint_op_to_string(unsigned char op) {
177 0           switch (op) {
178             case SQLITE_INDEX_CONSTRAINT_EQ:
179 0           return "=";
180             case SQLITE_INDEX_CONSTRAINT_GT:
181 0           return ">";
182             case SQLITE_INDEX_CONSTRAINT_GE:
183 0           return ">=";
184             case SQLITE_INDEX_CONSTRAINT_LT:
185 0           return "<";
186             case SQLITE_INDEX_CONSTRAINT_LE:
187 0           return "<=";
188             case SQLITE_INDEX_CONSTRAINT_MATCH:
189 0           return "MATCH";
190             #if SQLITE_VERSION_NUMBER >= 3010000
191             case SQLITE_INDEX_CONSTRAINT_LIKE:
192 0           return "LIKE";
193             case SQLITE_INDEX_CONSTRAINT_GLOB:
194 0           return "GLOB";
195             case SQLITE_INDEX_CONSTRAINT_REGEXP:
196 0           return "REGEXP";
197             #endif
198             #if SQLITE_VERSION_NUMBER >= 3021000
199             case SQLITE_INDEX_CONSTRAINT_NE:
200 0           return "NE";
201             case SQLITE_INDEX_CONSTRAINT_ISNOT:
202 0           return "ISNOT";
203             case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
204 0           return "ISNOTNULL";
205             case SQLITE_INDEX_CONSTRAINT_ISNULL:
206 0           return "ISNULL";
207             case SQLITE_INDEX_CONSTRAINT_IS:
208 0           return "IS";
209             #endif
210             default:
211 0           return "unknown";
212             }
213             }
214              
215              
216 0           static int perl_vt_BestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pIdxInfo){
217             dTHX;
218 0           dSP;
219             int i, count;
220             int argvIndex;
221             AV *constraints;
222             AV *order_by;
223             SV *hashref;
224             SV **val;
225             HV *hv;
226             struct sqlite3_index_constraint_usage *pConsUsage;
227              
228 0           ENTER;
229 0           SAVETMPS;
230              
231             /* build the "where_constraints" datastructure */
232 0           constraints = newAV();
233 0 0         for (i=0; inConstraint; i++){
234 0           struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[i];
235 0           HV *constraint = newHV();
236 0           char *op_str = _constraint_op_to_string(pCons->op);
237 0           hv_stores(constraint, "col", newSViv(pCons->iColumn));
238 0           hv_stores(constraint, "op", newSVpv(op_str, 0));
239 0 0         hv_stores(constraint, "usable", pCons->usable ? &PL_sv_yes : &PL_sv_no);
240 0           av_push(constraints, newRV_noinc((SV*) constraint));
241             }
242              
243             /* build the "order_by" datastructure */
244 0           order_by = newAV();
245 0 0         for (i=0; inOrderBy; i++){
246 0           struct sqlite3_index_orderby const *pOrder = &pIdxInfo->aOrderBy[i];
247 0           HV *order = newHV();
248 0           hv_stores(order, "col", newSViv(pOrder->iColumn));
249 0 0         hv_stores(order, "desc", pOrder->desc ? &PL_sv_yes : &PL_sv_no);
250 0           av_push( order_by, newRV_noinc((SV*) order));
251             }
252              
253             /* call the ->BEST_INDEX() method */
254 0 0         PUSHMARK(SP);
255 0 0         XPUSHs( ((perl_vtab *) pVTab)->perl_vtab_obj);
256 0 0         XPUSHs( sv_2mortal( newRV_noinc((SV*) constraints)));
257 0 0         XPUSHs( sv_2mortal( newRV_noinc((SV*) order_by)));
258 0           PUTBACK;
259 0           count = call_method ("BEST_INDEX", G_SCALAR);
260 0           SPAGAIN;
261              
262             /* get values back from the returned hashref */
263 0 0         if (count != 1)
264 0           croak("BEST_INDEX() method returned %d vals instead of 1", count);
265 0           hashref = POPs;
266 0 0         if (!(hashref && SvROK(hashref) && SvTYPE(SvRV(hashref)) == SVt_PVHV))
    0          
    0          
267 0           croak("BEST_INDEX() method did not return a hashref");
268 0           hv = (HV*)SvRV(hashref);
269 0           val = hv_fetch(hv, "idxNum", 6, FALSE);
270 0 0         pIdxInfo->idxNum = (val && SvOK(*val)) ? SvIV(*val) : 0;
    0          
    0          
    0          
    0          
271 0           val = hv_fetch(hv, "idxStr", 6, FALSE);
272 0 0         if (val && SvOK(*val)) {
    0          
    0          
    0          
273             STRLEN len;
274 0 0         char *str = SvPVutf8(*val, len);
275 0           pIdxInfo->idxStr = sqlite3_malloc(len+1);
276 0           memcpy(pIdxInfo->idxStr, str, len);
277 0           pIdxInfo->idxStr[len] = 0;
278 0           pIdxInfo->needToFreeIdxStr = 1;
279             }
280 0           val = hv_fetch(hv, "orderByConsumed", 15, FALSE);
281 0 0         pIdxInfo->orderByConsumed = (val && SvTRUE(*val)) ? 1 : 0;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
282 0           val = hv_fetch(hv, "estimatedCost", 13, FALSE);
283 0 0         pIdxInfo->estimatedCost = (val && SvOK(*val)) ? SvNV(*val) : 0;
    0          
    0          
    0          
    0          
284             #if SQLITE_VERSION_NUMBER >= 3008002
285 0           val = hv_fetch(hv, "estimatedRows", 13, FALSE);
286 0 0         pIdxInfo->estimatedRows = (val && SvOK(*val)) ? SvIV(*val) : 0;
    0          
    0          
    0          
    0          
287             #endif
288              
289             /* loop over constraints to get back the "argvIndex" and "omit" keys
290             that shoud have been added by the best_index() method call */
291 0 0         for (i=0; inConstraint; i++){
292 0           SV **rv = av_fetch(constraints, i, FALSE);
293 0 0         if (!(rv && SvROK(*rv) && SvTYPE(SvRV(*rv)) == SVt_PVHV))
    0          
    0          
294 0           croak("the call to BEST_INDEX() has corrupted constraint data");
295 0           hv = (HV*)SvRV(*rv);
296 0           val = hv_fetch(hv, "argvIndex", 9, FALSE);
297 0 0         argvIndex = (val && SvOK(*val)) ? SvIV(*val) + 1: 0;
    0          
    0          
    0          
    0          
298              
299 0           pConsUsage = &pIdxInfo->aConstraintUsage[i];
300 0           pConsUsage->argvIndex = argvIndex;
301 0           val = hv_fetch(hv, "omit", 4, FALSE);
302 0 0         pConsUsage->omit = (val && SvTRUE(*val)) ? 1 : 0;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
303             }
304              
305 0           PUTBACK;
306 0 0         FREETMPS;
307 0           LEAVE;
308              
309 0           return SQLITE_OK;
310             }
311              
312              
313              
314 0           static int perl_vt_Open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
315             dTHX;
316 0           dSP;
317             int count;
318 0           int rc = SQLITE_ERROR;
319             SV *perl_cursor;
320             perl_vtab_cursor *cursor;
321              
322 0           ENTER;
323 0           SAVETMPS;
324              
325             /* allocate a perl_vtab_cursor structure */
326 0           cursor = (perl_vtab_cursor *) sqlite3_malloc(sizeof(*cursor));
327 0 0         if( cursor==NULL ) return SQLITE_NOMEM;
328 0           memset(cursor, 0, sizeof(*cursor));
329              
330             /* call the ->OPEN() method */
331 0 0         PUSHMARK(SP);
332 0 0         XPUSHs( ((perl_vtab *) pVTab)->perl_vtab_obj);
333 0           PUTBACK;
334 0           count = call_method ("OPEN", G_SCALAR);
335 0           SPAGAIN;
336 0 0         if (count != 1) {
337 0           warn("vtab->OPEN() method returned %d vals instead of 1", count);
338 0           SP -= count;
339 0           goto cleanup;
340              
341             }
342 0           perl_cursor = POPs;
343 0 0         if ( !sv_isobject(perl_cursor) ) {
344 0           warn("vtab->OPEN() method did not return a blessed cursor");
345 0           goto cleanup;
346             }
347              
348             /* everything went OK */
349 0           rc = SQLITE_OK;
350              
351             cleanup:
352              
353 0 0         if (rc == SQLITE_OK) {
354 0           cursor->perl_cursor_obj = SvREFCNT_inc(perl_cursor);
355 0           *ppCursor = &cursor->base;
356             }
357             else {
358 0           sqlite3_free(cursor);
359             }
360              
361 0           PUTBACK;
362 0 0         FREETMPS;
363 0           LEAVE;
364              
365 0           return rc;
366             }
367              
368 0           static int perl_vt_Close(sqlite3_vtab_cursor *pVtabCursor){
369             dTHX;
370 0           dSP;
371             perl_vtab_cursor *perl_pVTabCursor;
372              
373 0           ENTER;
374 0           SAVETMPS;
375              
376             /* Note : there is no explicit call to a CLOSE() method; if
377             needed, the Perl class can implement a DESTROY() method */
378              
379 0           perl_pVTabCursor = (perl_vtab_cursor *) pVtabCursor;
380 0           SvREFCNT_dec(perl_pVTabCursor->perl_cursor_obj);
381 0           sqlite3_free(perl_pVTabCursor);
382              
383 0           PUTBACK;
384 0 0         FREETMPS;
385 0           LEAVE;
386              
387 0           return SQLITE_OK;
388             }
389              
390 0           static int perl_vt_Filter( sqlite3_vtab_cursor *pVtabCursor,
391             int idxNum, const char *idxStr,
392             int argc, sqlite3_value **argv ){
393             dTHX;
394 0           dSP;
395             dMY_CXT;
396             int i, count;
397 0           int is_unicode = MY_CXT.last_dbh_is_unicode;
398              
399 0           ENTER;
400 0           SAVETMPS;
401              
402             /* call the FILTER() method with ($idxNum, $idxStr, @args) */
403 0 0         PUSHMARK(SP);
404 0 0         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
405 0 0         XPUSHs(sv_2mortal(newSViv(idxNum)));
406 0 0         XPUSHs(sv_2mortal(newSVpv(idxStr, 0)));
407 0 0         for(i = 0; i < argc; i++) {
408 0 0         XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], is_unicode));
409             }
410 0           PUTBACK;
411 0           count = call_method("FILTER", G_VOID);
412 0           SPAGAIN;
413 0           SP -= count;
414              
415 0           PUTBACK;
416 0 0         FREETMPS;
417 0           LEAVE;
418              
419 0           return SQLITE_OK;
420             }
421              
422              
423 0           static int perl_vt_Next(sqlite3_vtab_cursor *pVtabCursor){
424             dTHX;
425 0           dSP;
426             int count;
427              
428 0           ENTER;
429 0           SAVETMPS;
430              
431             /* call the next() method */
432 0 0         PUSHMARK(SP);
433 0 0         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
434 0           PUTBACK;
435 0           count = call_method ("NEXT", G_VOID);
436 0           SPAGAIN;
437 0           SP -= count;
438              
439 0           PUTBACK;
440 0 0         FREETMPS;
441 0           LEAVE;
442              
443 0           return SQLITE_OK;
444             }
445              
446 0           static int perl_vt_Eof(sqlite3_vtab_cursor *pVtabCursor){
447             dTHX;
448 0           dSP;
449             int count, eof;
450              
451 0           ENTER;
452 0           SAVETMPS;
453              
454             /* call the eof() method */
455 0 0         PUSHMARK(SP);
456 0 0         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
457 0           PUTBACK;
458 0           count = call_method ("EOF", G_SCALAR);
459 0           SPAGAIN;
460 0 0         if (count != 1) {
461 0           warn("cursor->EOF() method returned %d vals instead of 1", count);
462 0           SP -= count;
463             }
464             else {
465 0           SV *sv = POPs; /* need 2 lines, because this doesn't work : */
466 0 0         eof = SvTRUE(sv); /* eof = SvTRUE(POPs); # I don't understand why :-( */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
467             }
468              
469 0           PUTBACK;
470 0 0         FREETMPS;
471 0           LEAVE;
472              
473 0           return eof;
474             }
475              
476              
477 0           static int perl_vt_Column(sqlite3_vtab_cursor *pVtabCursor,
478             sqlite3_context* context,
479             int col){
480             dTHX;
481 0           dSP;
482             int count;
483 0           int rc = SQLITE_ERROR;
484              
485 0           ENTER;
486 0           SAVETMPS;
487              
488             /* call the column() method */
489 0 0         PUSHMARK(SP);
490 0 0         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
491 0 0         XPUSHs(sv_2mortal(newSViv(col)));
492 0           PUTBACK;
493 0           count = call_method ("COLUMN", G_SCALAR);
494 0           SPAGAIN;
495 0 0         if (count != 1) {
496 0           warn("cursor->COLUMN() method returned %d vals instead of 1", count);
497 0           SP -= count;
498 0           sqlite3_result_error(context, "column error", 12);
499             }
500             else {
501 0           SV *result = POPs;
502 0           sqlite_set_result(aTHX_ context, result, 0 );
503 0           rc = SQLITE_OK;
504             }
505              
506 0           PUTBACK;
507 0 0         FREETMPS;
508 0           LEAVE;
509              
510 0           return rc;
511             }
512              
513 0           static int perl_vt_Rowid( sqlite3_vtab_cursor *pVtabCursor,
514             sqlite3_int64 *pRowid ){
515             dTHX;
516 0           dSP;
517             int count;
518 0           int rc = SQLITE_ERROR;
519              
520 0           ENTER;
521 0           SAVETMPS;
522              
523             /* call the rowid() method */
524 0 0         PUSHMARK(SP);
525 0 0         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
526 0           PUTBACK;
527 0           count = call_method ("ROWID", G_SCALAR);
528 0           SPAGAIN;
529 0 0         if (count != 1) {
530 0           warn("cursor->ROWID() returned %d vals instead of 1", count);
531 0           SP -= count;
532             }
533             else {
534 0 0         *pRowid =POPi;
535 0           rc = SQLITE_OK;
536             }
537              
538 0           PUTBACK;
539 0 0         FREETMPS;
540 0           LEAVE;
541              
542 0           return rc;
543             }
544              
545 0           static int perl_vt_Update( sqlite3_vtab *pVTab,
546             int argc, sqlite3_value **argv,
547             sqlite3_int64 *pRowid ){
548             dTHX;
549 0           dSP;
550             dMY_CXT;
551             int count, i;
552 0           int is_unicode = MY_CXT.last_dbh_is_unicode;
553 0           int rc = SQLITE_ERROR;
554             SV *rowidsv;
555              
556 0           ENTER;
557 0           SAVETMPS;
558              
559             /* call the _SQLITE_UPDATE() method */
560 0 0         PUSHMARK(SP);
561 0 0         XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj);
562 0 0         for(i = 0; i < argc; i++) {
563 0 0         XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], is_unicode));
564             }
565 0           PUTBACK;
566 0           count = call_method ("_SQLITE_UPDATE", G_SCALAR);
567 0           SPAGAIN;
568 0 0         if (count != 1) {
569 0           warn("cursor->_SQLITE_UPDATE() returned %d vals instead of 1", count);
570 0           SP -= count;
571             }
572             else {
573 0 0         if (argc > 1 && sqlite3_value_type(argv[0]) == SQLITE_NULL
    0          
574 0 0         && sqlite3_value_type(argv[1]) == SQLITE_NULL) {
575             /* this was an insert without any given rowid, so the result of
576             the method call must be passed in *pRowid*/
577 0           rowidsv = POPs;
578 0 0         if (!SvOK(rowidsv))
    0          
    0          
579 0           *pRowid = 0;
580 0 0         else if (SvUOK(rowidsv))
581 0 0         *pRowid = SvUV(rowidsv);
582 0 0         else if (SvIOK(rowidsv))
583 0 0         *pRowid = SvIV(rowidsv);
584             else
585 0 0         *pRowid = (sqlite3_int64)SvNV(rowidsv);
586             }
587 0           rc = SQLITE_OK;
588             }
589              
590              
591 0           PUTBACK;
592 0 0         FREETMPS;
593 0           LEAVE;
594              
595 0           return rc;
596             }
597              
598 0           static int perl_vt_Begin(sqlite3_vtab *pVTab){
599 0           return _call_perl_vtab_method(pVTab, "BEGIN_TRANSACTION", 0);
600             }
601              
602 0           static int perl_vt_Sync(sqlite3_vtab *pVTab){
603 0           return _call_perl_vtab_method(pVTab, "SYNC_TRANSACTION", 0);
604             }
605              
606 0           static int perl_vt_Commit(sqlite3_vtab *pVTab){
607 0           return _call_perl_vtab_method(pVTab, "COMMIT_TRANSACTION", 0);
608             }
609              
610 0           static int perl_vt_Rollback(sqlite3_vtab *pVTab){
611 0           return _call_perl_vtab_method(pVTab, "ROLLBACK_TRANSACTION", 0);
612             }
613              
614 0           static int perl_vt_FindFunction(sqlite3_vtab *pVTab,
615             int nArg, const char *zName,
616             void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
617             void **ppArg){
618             dTHX;
619 0           dSP;
620             dMY_CXT;
621             int count;
622 0           int is_overloaded = 0;
623 0           char *func_name = sqlite3_mprintf("%s\t%d", zName, nArg);
624 0           STRLEN len = strlen(func_name);
625 0           HV *functions = ((perl_vtab *) pVTab)->functions;
626 0           SV* coderef = NULL;
627             SV** val;
628             SV *result;
629              
630 0           ENTER;
631 0           SAVETMPS;
632              
633             /* check if that function was already in cache */
634 0 0         if (hv_exists(functions, func_name, len)) {
635 0           val = hv_fetch(functions, func_name, len, FALSE);
636 0 0         if (val && SvOK(*val)) {
    0          
    0          
    0          
637 0           coderef = *val;
638             }
639             }
640             else {
641             /* call the FIND_FUNCTION() method */
642 0 0         PUSHMARK(SP);
643 0 0         XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj);
644 0 0         XPUSHs(sv_2mortal(newSViv(nArg)));
645 0 0         XPUSHs(sv_2mortal(newSVpv(zName, 0)));
646 0           PUTBACK;
647 0           count = call_method ("FIND_FUNCTION", G_SCALAR);
648 0           SPAGAIN;
649 0 0         if (count != 1) {
650 0           warn("vtab->FIND_FUNCTION() method returned %d vals instead of 1", count);
651 0           SP -= count;
652 0           goto cleanup;
653             }
654 0           result = POPs;
655 0 0         if (SvTRUE(result)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
656             /* the coderef must be valid for the lifetime of pVTab, so
657             make a copy */
658 0           coderef = newSVsv(result);
659             }
660              
661             /* store result in cache */
662 0 0         hv_store(functions, func_name, len, coderef ? coderef : &PL_sv_undef, 0);
663             }
664              
665             /* return function information for sqlite3 within *pxFunc and *ppArg */
666 0 0         is_overloaded = coderef && SvTRUE(coderef);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
667 0 0         if (is_overloaded) {
668 0           *pxFunc = MY_CXT.last_dbh_is_unicode ? sqlite_db_func_dispatcher_unicode
669 0 0         : sqlite_db_func_dispatcher_no_unicode;
670 0           *ppArg = coderef;
671             }
672              
673             cleanup:
674 0           PUTBACK;
675 0 0         FREETMPS;
676 0           LEAVE;
677 0           sqlite3_free(func_name);
678 0           return is_overloaded;
679             }
680              
681              
682 0           static int perl_vt_Rename(sqlite3_vtab *pVTab, const char *zNew){
683             dTHX;
684 0           dSP;
685             int count;
686 0           int rc = SQLITE_ERROR;
687              
688 0           ENTER;
689 0           SAVETMPS;
690              
691 0 0         PUSHMARK(SP);
692 0 0         XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj);
693 0 0         XPUSHs(sv_2mortal(newSVpv(zNew, 0)));
694 0           PUTBACK;
695 0           count = call_method("RENAME", G_SCALAR);
696 0           SPAGAIN;
697 0 0         if (count != 1) {
698 0           warn("vtab->RENAME() returned %d args instead of 1", count);
699 0           SP -= count;
700             }
701             else {
702 0 0         rc = POPi;
703             }
704              
705 0           PUTBACK;
706 0 0         FREETMPS;
707 0           LEAVE;
708              
709 0           return rc;
710             }
711              
712 0           static int perl_vt_Savepoint(sqlite3_vtab *pVTab, int point){
713 0           return _call_perl_vtab_method(pVTab, "SAVEPOINT", point);
714             }
715              
716 0           static int perl_vt_Release(sqlite3_vtab *pVTab, int point){
717 0           return _call_perl_vtab_method(pVTab, "RELEASE", point);
718             }
719              
720 0           static int perl_vt_RollbackTo(sqlite3_vtab *pVTab, int point){
721 0           return _call_perl_vtab_method(pVTab, "ROLLBACK_TO", point);
722             }
723              
724             static sqlite3_module perl_vt_Module = {
725             1, /* iVersion */
726             perl_vt_Create, /* xCreate */
727             perl_vt_Connect, /* xConnect */
728             perl_vt_BestIndex, /* xBestIndex */
729             perl_vt_Disconnect, /* xDisconnect */
730             perl_vt_Drop, /* xDestroy */
731             perl_vt_Open, /* xOpen - open a cursor */
732             perl_vt_Close, /* xClose - close a cursor */
733             perl_vt_Filter, /* xFilter - configure scan constraints */
734             perl_vt_Next, /* xNext - advance a cursor */
735             perl_vt_Eof, /* xEof - check for end of scan */
736             perl_vt_Column, /* xColumn - read data */
737             perl_vt_Rowid, /* xRowid - read data */
738             perl_vt_Update, /* xUpdate (optional) */
739             perl_vt_Begin, /* xBegin (optional) */
740             perl_vt_Sync, /* xSync (optional) */
741             perl_vt_Commit, /* xCommit (optional) */
742             perl_vt_Rollback, /* xRollback (optional) */
743             perl_vt_FindFunction, /* xFindFunction (optional) */
744             perl_vt_Rename, /* xRename */
745             #if SQLITE_VERSION_NUMBER >= 3007007
746             perl_vt_Savepoint, /* xSavepoint (optional) */
747             perl_vt_Release, /* xRelease (optional) */
748             perl_vt_RollbackTo /* xRollbackTo (optional) */
749             #endif
750             };
751              
752              
753             void
754 0           sqlite_db_destroy_module_data(void *pAux)
755             {
756             dTHX;
757 0           dSP;
758             int count;
759 0           int rc = SQLITE_ERROR;
760             perl_vtab_init *init_data;
761              
762 0           ENTER;
763 0           SAVETMPS;
764              
765 0           init_data = (perl_vtab_init *)pAux;
766              
767             /* call the DESTROY_MODULE() method */
768 0 0         PUSHMARK(SP);
769 0 0         XPUSHs(sv_2mortal(newSVpv(init_data->perl_class, 0)));
770 0           PUTBACK;
771 0           count = call_method("DESTROY_MODULE", G_VOID);
772 0           SPAGAIN;
773 0           SP -= count;
774              
775             /* free module memory */
776 0           SvREFCNT_dec(init_data->dbh);
777 0           sqlite3_free((char *)init_data->perl_class);
778              
779 0           PUTBACK;
780 0 0         FREETMPS;
781 0           LEAVE;
782 0           }
783              
784              
785              
786             int
787 0           sqlite_db_create_module(pTHX_ SV *dbh, const char *name, const char *perl_class)
788             {
789 0           dSP;
790 0           D_imp_dbh(dbh);
791 0           int count, rc, retval = TRUE;
792             char *module_ISA;
793             char *loading_code;
794             perl_vtab_init *init_data;
795              
796 0           ENTER;
797 0           SAVETMPS;
798              
799 0 0         if (!DBIc_ACTIVE(imp_dbh)) {
800 0           sqlite_error(dbh, -2, "attempt to create module on inactive database handle");
801 0           return FALSE;
802             }
803              
804             /* load the module if needed */
805 0           module_ISA = sqlite3_mprintf("%s::ISA", perl_class);
806 0 0         if (!get_av(module_ISA, 0)) {
807 0           loading_code = sqlite3_mprintf("use %s", perl_class);
808 0           eval_pv(loading_code, TRUE);
809 0           sqlite3_free(loading_code);
810             }
811 0           sqlite3_free(module_ISA);
812              
813             /* build the init datastructure that will be passed to perl_vt_New() */
814 0           init_data = sqlite3_malloc(sizeof(*init_data));
815 0           init_data->dbh = newRV(dbh);
816 0           sv_rvweaken(init_data->dbh);
817 0           init_data->perl_class = sqlite3_mprintf(perl_class);
818              
819             /* register within sqlite */
820 0           rc = sqlite3_create_module_v2( imp_dbh->db,
821             name,
822             &perl_vt_Module,
823             init_data,
824             sqlite_db_destroy_module_data
825             );
826 0 0         if ( rc != SQLITE_OK ) {
827 0           sqlite_error(dbh, rc, form("sqlite_create_module failed with error %s",
828             sqlite3_errmsg(imp_dbh->db)));
829 0           retval = FALSE;
830             }
831              
832              
833             /* call the CREATE_MODULE() method */
834 0 0         PUSHMARK(SP);
835 0 0         XPUSHs(sv_2mortal(newSVpv(perl_class, 0)));
836 0 0         XPUSHs(sv_2mortal(newSVpv(name, 0)));
837 0           PUTBACK;
838 0           count = call_method("CREATE_MODULE", G_VOID);
839 0           SPAGAIN;
840 0           SP -= count;
841              
842 0           PUTBACK;
843 0 0         FREETMPS;
844 0           LEAVE;
845              
846 0           return retval;
847             }