File Coverage

dbdimp_virtual_table.inc
Criterion Covered Total %
statement 376 443 84.8
branch 188 468 40.1
condition n/a
subroutine n/a
pod n/a
total 564 911 61.9


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 50           static int _call_perl_vtab_method(sqlite3_vtab *pVTab,
26             const char *method, int i) {
27             dTHX;
28 50           dSP;
29             int count;
30              
31 50           ENTER;
32 50           SAVETMPS;
33              
34 50 50         PUSHMARK(SP);
35 50 50         XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj);
36 50 50         XPUSHs(sv_2mortal(newSViv(i)));
37 50           PUTBACK;
38 50           count = call_method (method, G_VOID);
39 50           SPAGAIN;
40 50           SP -= count;
41              
42 50           PUTBACK;
43 50 50         FREETMPS;
44 50           LEAVE;
45              
46 50           return SQLITE_OK;
47             }
48              
49              
50              
51 15           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 15           dSP;
57             perl_vtab *vt;
58 15           perl_vtab_init *init_data = (perl_vtab_init *)pAux;
59             int count, i;
60 15           int rc = SQLITE_ERROR;
61             SV *perl_vtab_obj;
62             SV *sql;
63              
64             /* allocate a perl_vtab structure */
65 15           vt = (perl_vtab *) sqlite3_malloc(sizeof(*vt));
66 15 50         if( vt==NULL ) return SQLITE_NOMEM;
67 15           memset(vt, 0, sizeof(*vt));
68 15           vt->functions = newHV();
69              
70 15           ENTER;
71 15           SAVETMPS;
72              
73             /* call the ->CREATE/CONNECT() method */
74 15 50         PUSHMARK(SP);
75 15 50         XPUSHs(sv_2mortal(newSVpv(init_data->perl_class, 0)));
76 15 50         XPUSHs(init_data->dbh);
77 103 100         for(i = 0; i < argc; i++) {
78 88 50         XPUSHs(newSVpvn_flags(argv[i], strlen(argv[i]), SVs_TEMP|SVf_UTF8));
79             }
80 15           PUTBACK;
81 15           count = call_method (method, G_SCALAR);
82 15           SPAGAIN;
83              
84             /* check the return value */
85 15 50         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 15           perl_vtab_obj = POPs;
94 15 50         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 15 50         PUSHMARK(SP);
102 15 50         XPUSHs(perl_vtab_obj);
103 15           PUTBACK;
104 15           count = call_method ("VTAB_TO_DECLARE", G_SCALAR);
105 15           SPAGAIN;
106              
107             /* check the return value */
108 15 50         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 15           sql = POPs;
118 15 50         rc = sqlite3_declare_vtab(db, SvPVutf8_nolen(sql));
119              
120             cleanup:
121 15 50         if (rc == SQLITE_OK) {
122             /* record the VirtualTable perl instance within the vtab structure */
123 15           vt->perl_vtab_obj = SvREFCNT_inc(perl_vtab_obj);
124 15           *ppVTab = &vt->base;
125             }
126             else {
127 0           sqlite3_free(vt);
128             }
129              
130 15           PUTBACK;
131 15 50         FREETMPS;
132 15           LEAVE;
133              
134 15           return rc;
135             }
136              
137              
138 13           static int perl_vt_Create(sqlite3 *db, void *pAux,
139             int argc, const char *const *argv,
140             sqlite3_vtab **ppVTab, char **pzErr){
141 13           return perl_vt_New("CREATE", db, pAux, argc, argv, ppVTab, pzErr);
142             }
143              
144 2           static int perl_vt_Connect(sqlite3 *db, void *pAux,
145             int argc, const char *const *argv,
146             sqlite3_vtab **ppVTab, char **pzErr){
147 2           return perl_vt_New("CONNECT", db, pAux, argc, argv, ppVTab, pzErr);
148             }
149              
150              
151 15           static int _free_perl_vtab(perl_vtab *pVTab){
152             dTHX;
153              
154 15           SvREFCNT_dec(pVTab->perl_vtab_obj);
155              
156             /* deallocate coderefs that were declared through FindFunction() */
157 15           hv_undef(pVTab->functions);
158 15           SvREFCNT_dec(pVTab->functions);
159              
160 15           sqlite3_free(pVTab);
161 15           return SQLITE_OK;
162             }
163              
164 13           static int perl_vt_Disconnect(sqlite3_vtab *pVTab){
165 13           _call_perl_vtab_method(pVTab, "DISCONNECT", 0);
166 13           return _free_perl_vtab((perl_vtab *)pVTab);
167             }
168              
169 2           static int perl_vt_Drop(sqlite3_vtab *pVTab){
170 2           _call_perl_vtab_method(pVTab, "DROP", 0);
171 2           return _free_perl_vtab((perl_vtab *)pVTab);
172             }
173              
174              
175             static char *
176 54           _constraint_op_to_string(unsigned char op) {
177 54           switch (op) {
178             case SQLITE_INDEX_CONSTRAINT_EQ:
179 17           return "=";
180             case SQLITE_INDEX_CONSTRAINT_GT:
181 2           return ">";
182             case SQLITE_INDEX_CONSTRAINT_GE:
183 1           return ">=";
184             case SQLITE_INDEX_CONSTRAINT_LT:
185 4           return "<";
186             case SQLITE_INDEX_CONSTRAINT_LE:
187 1           return "<=";
188             case SQLITE_INDEX_CONSTRAINT_MATCH:
189 20           return "MATCH";
190             #if SQLITE_VERSION_NUMBER >= 3010000
191             case SQLITE_INDEX_CONSTRAINT_LIKE:
192 2           return "LIKE";
193             case SQLITE_INDEX_CONSTRAINT_GLOB:
194 0           return "GLOB";
195             case SQLITE_INDEX_CONSTRAINT_REGEXP:
196 1           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 1           return "ISNOT";
203             case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
204 2           return "ISNOTNULL";
205             case SQLITE_INDEX_CONSTRAINT_ISNULL:
206 2           return "ISNULL";
207             case SQLITE_INDEX_CONSTRAINT_IS:
208 1           return "IS";
209             #endif
210             default:
211 0           return "unknown";
212             }
213             }
214              
215              
216 64           static int perl_vt_BestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pIdxInfo){
217             dTHX;
218 64           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 64           ENTER;
229 64           SAVETMPS;
230              
231             /* build the "where_constraints" datastructure */
232 64           constraints = newAV();
233 118 100         for (i=0; inConstraint; i++){
234 54           struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[i];
235 54           HV *constraint = newHV();
236 54           char *op_str = _constraint_op_to_string(pCons->op);
237 54           hv_stores(constraint, "col", newSViv(pCons->iColumn));
238 54           hv_stores(constraint, "op", newSVpv(op_str, 0));
239 54 50         hv_stores(constraint, "usable", pCons->usable ? &PL_sv_yes : &PL_sv_no);
240 54           av_push(constraints, newRV_noinc((SV*) constraint));
241             }
242              
243             /* build the "order_by" datastructure */
244 64           order_by = newAV();
245 85 100         for (i=0; inOrderBy; i++){
246 21           struct sqlite3_index_orderby const *pOrder = &pIdxInfo->aOrderBy[i];
247 21           HV *order = newHV();
248 21           hv_stores(order, "col", newSViv(pOrder->iColumn));
249 21 100         hv_stores(order, "desc", pOrder->desc ? &PL_sv_yes : &PL_sv_no);
250 21           av_push( order_by, newRV_noinc((SV*) order));
251             }
252              
253             /* call the ->BEST_INDEX() method */
254 64 50         PUSHMARK(SP);
255 64 50         XPUSHs( ((perl_vtab *) pVTab)->perl_vtab_obj);
256 64 50         XPUSHs( sv_2mortal( newRV_noinc((SV*) constraints)));
257 64 50         XPUSHs( sv_2mortal( newRV_noinc((SV*) order_by)));
258 64           PUTBACK;
259 64           count = call_method ("BEST_INDEX", G_SCALAR);
260 64           SPAGAIN;
261              
262             /* get values back from the returned hashref */
263 64 50         if (count != 1)
264 0           croak("BEST_INDEX() method returned %d vals instead of 1", count);
265 64           hashref = POPs;
266 64 50         if (!(hashref && SvROK(hashref) && SvTYPE(SvRV(hashref)) == SVt_PVHV))
    50          
    50          
267 0           croak("BEST_INDEX() method did not return a hashref");
268 64           hv = (HV*)SvRV(hashref);
269 64           val = hv_fetch(hv, "idxNum", 6, FALSE);
270 64 50         pIdxInfo->idxNum = (val && SvOK(*val)) ? SvIV(*val) : 0;
    50          
    0          
    0          
    50          
271 64           val = hv_fetch(hv, "idxStr", 6, FALSE);
272 64 50         if (val && SvOK(*val)) {
    50          
    0          
    0          
273             STRLEN len;
274 64 50         char *str = SvPVutf8(*val, len);
275 64           pIdxInfo->idxStr = sqlite3_malloc(len+1);
276 64           memcpy(pIdxInfo->idxStr, str, len);
277 64           pIdxInfo->idxStr[len] = 0;
278 64           pIdxInfo->needToFreeIdxStr = 1;
279             }
280 64           val = hv_fetch(hv, "orderByConsumed", 15, FALSE);
281 64 50         pIdxInfo->orderByConsumed = (val && SvTRUE(*val)) ? 1 : 0;
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
282 64           val = hv_fetch(hv, "estimatedCost", 13, FALSE);
283 64 50         pIdxInfo->estimatedCost = (val && SvOK(*val)) ? SvNV(*val) : 0;
    50          
    0          
    0          
    50          
284             #if SQLITE_VERSION_NUMBER >= 3008002
285 64           val = hv_fetch(hv, "estimatedRows", 13, FALSE);
286 64 50         pIdxInfo->estimatedRows = (val && SvOK(*val)) ? SvIV(*val) : 0;
    50          
    50          
    50          
    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 118 100         for (i=0; inConstraint; i++){
292 54           SV **rv = av_fetch(constraints, i, FALSE);
293 54 50         if (!(rv && SvROK(*rv) && SvTYPE(SvRV(*rv)) == SVt_PVHV))
    50          
    50          
294 0           croak("the call to BEST_INDEX() has corrupted constraint data");
295 54           hv = (HV*)SvRV(*rv);
296 54           val = hv_fetch(hv, "argvIndex", 9, FALSE);
297 54 100         argvIndex = (val && SvOK(*val)) ? SvIV(*val) + 1: 0;
    50          
    0          
    0          
    50          
298              
299 54           pConsUsage = &pIdxInfo->aConstraintUsage[i];
300 54           pConsUsage->argvIndex = argvIndex;
301 54           val = hv_fetch(hv, "omit", 4, FALSE);
302 54 100         pConsUsage->omit = (val && SvTRUE(*val)) ? 1 : 0;
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
303             }
304              
305 64           PUTBACK;
306 64 50         FREETMPS;
307 64           LEAVE;
308              
309 64           return SQLITE_OK;
310             }
311              
312              
313              
314 107           static int perl_vt_Open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
315             dTHX;
316 107           dSP;
317             int count;
318 107           int rc = SQLITE_ERROR;
319             SV *perl_cursor;
320             perl_vtab_cursor *cursor;
321              
322 107           ENTER;
323 107           SAVETMPS;
324              
325             /* allocate a perl_vtab_cursor structure */
326 107           cursor = (perl_vtab_cursor *) sqlite3_malloc(sizeof(*cursor));
327 107 50         if( cursor==NULL ) return SQLITE_NOMEM;
328 107           memset(cursor, 0, sizeof(*cursor));
329              
330             /* call the ->OPEN() method */
331 107 50         PUSHMARK(SP);
332 107 50         XPUSHs( ((perl_vtab *) pVTab)->perl_vtab_obj);
333 107           PUTBACK;
334 107           count = call_method ("OPEN", G_SCALAR);
335 107           SPAGAIN;
336 107 50         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 107           perl_cursor = POPs;
343 107 50         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 107           rc = SQLITE_OK;
350              
351             cleanup:
352              
353 107 50         if (rc == SQLITE_OK) {
354 107           cursor->perl_cursor_obj = SvREFCNT_inc(perl_cursor);
355 107           *ppCursor = &cursor->base;
356             }
357             else {
358 0           sqlite3_free(cursor);
359             }
360              
361 107           PUTBACK;
362 107 50         FREETMPS;
363 107           LEAVE;
364              
365 107           return rc;
366             }
367              
368 107           static int perl_vt_Close(sqlite3_vtab_cursor *pVtabCursor){
369             dTHX;
370 107           dSP;
371             perl_vtab_cursor *perl_pVTabCursor;
372              
373 107           ENTER;
374 107           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 107           perl_pVTabCursor = (perl_vtab_cursor *) pVtabCursor;
380 107           SvREFCNT_dec(perl_pVTabCursor->perl_cursor_obj);
381 107           sqlite3_free(perl_pVTabCursor);
382              
383 107           PUTBACK;
384 107 100         FREETMPS;
385 107           LEAVE;
386              
387 107           return SQLITE_OK;
388             }
389              
390 116           static int perl_vt_Filter( sqlite3_vtab_cursor *pVtabCursor,
391             int idxNum, const char *idxStr,
392             int argc, sqlite3_value **argv ){
393             dTHX;
394 116           dSP;
395             dMY_CXT;
396             int i, count;
397 116           int is_unicode = MY_CXT.last_dbh_is_unicode;
398              
399 116           ENTER;
400 116           SAVETMPS;
401              
402             /* call the FILTER() method with ($idxNum, $idxStr, @args) */
403 116 50         PUSHMARK(SP);
404 116 50         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
405 116 50         XPUSHs(sv_2mortal(newSViv(idxNum)));
406 116 50         XPUSHs(sv_2mortal(newSVpv(idxStr, 0)));
407 224 100         for(i = 0; i < argc; i++) {
408 108 50         XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], is_unicode));
409             }
410 116           PUTBACK;
411 116           count = call_method("FILTER", G_VOID);
412 116           SPAGAIN;
413 116           SP -= count;
414              
415 116           PUTBACK;
416 116 50         FREETMPS;
417 116           LEAVE;
418              
419 116           return SQLITE_OK;
420             }
421              
422              
423 142           static int perl_vt_Next(sqlite3_vtab_cursor *pVtabCursor){
424             dTHX;
425 142           dSP;
426             int count;
427              
428 142           ENTER;
429 142           SAVETMPS;
430              
431             /* call the next() method */
432 142 50         PUSHMARK(SP);
433 142 50         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
434 142           PUTBACK;
435 142           count = call_method ("NEXT", G_VOID);
436 142           SPAGAIN;
437 142           SP -= count;
438              
439 142           PUTBACK;
440 142 50         FREETMPS;
441 142           LEAVE;
442              
443 142           return SQLITE_OK;
444             }
445              
446 258           static int perl_vt_Eof(sqlite3_vtab_cursor *pVtabCursor){
447             dTHX;
448 258           dSP;
449             int count, eof;
450              
451 258           ENTER;
452 258           SAVETMPS;
453              
454             /* call the eof() method */
455 258 50         PUSHMARK(SP);
456 258 50         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
457 258           PUTBACK;
458 258           count = call_method ("EOF", G_SCALAR);
459 258           SPAGAIN;
460 258 50         if (count != 1) {
461 0           warn("cursor->EOF() method returned %d vals instead of 1", count);
462 0           SP -= count;
463             }
464             else {
465 258           SV *sv = POPs; /* need 2 lines, because this doesn't work : */
466 258 50         eof = SvTRUE(sv); /* eof = SvTRUE(POPs); # I don't understand why :-( */
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
467             }
468              
469 258           PUTBACK;
470 258 50         FREETMPS;
471 258           LEAVE;
472              
473 258           return eof;
474             }
475              
476              
477 461           static int perl_vt_Column(sqlite3_vtab_cursor *pVtabCursor,
478             sqlite3_context* context,
479             int col){
480             dTHX;
481 461           dSP;
482             int count;
483 461           int rc = SQLITE_ERROR;
484              
485 461           ENTER;
486 461           SAVETMPS;
487              
488             /* call the column() method */
489 461 50         PUSHMARK(SP);
490 461 50         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
491 461 50         XPUSHs(sv_2mortal(newSViv(col)));
492 461           PUTBACK;
493 461           count = call_method ("COLUMN", G_SCALAR);
494 461           SPAGAIN;
495 461 50         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 461           SV *result = POPs;
502 461           sqlite_set_result(aTHX_ context, result, 0 );
503 461           rc = SQLITE_OK;
504             }
505              
506 461           PUTBACK;
507 461 50         FREETMPS;
508 461           LEAVE;
509              
510 461           return rc;
511             }
512              
513 83           static int perl_vt_Rowid( sqlite3_vtab_cursor *pVtabCursor,
514             sqlite3_int64 *pRowid ){
515             dTHX;
516 83           dSP;
517             int count;
518 83           int rc = SQLITE_ERROR;
519              
520 83           ENTER;
521 83           SAVETMPS;
522              
523             /* call the rowid() method */
524 83 50         PUSHMARK(SP);
525 83 50         XPUSHs(((perl_vtab_cursor *) pVtabCursor)->perl_cursor_obj);
526 83           PUTBACK;
527 83           count = call_method ("ROWID", G_SCALAR);
528 83           SPAGAIN;
529 83 50         if (count != 1) {
530 0           warn("cursor->ROWID() returned %d vals instead of 1", count);
531 0           SP -= count;
532             }
533             else {
534 83 50         *pRowid =POPi;
535 83           rc = SQLITE_OK;
536             }
537              
538 83           PUTBACK;
539 83 50         FREETMPS;
540 83           LEAVE;
541              
542 83           return rc;
543             }
544              
545 5           static int perl_vt_Update( sqlite3_vtab *pVTab,
546             int argc, sqlite3_value **argv,
547             sqlite3_int64 *pRowid ){
548             dTHX;
549 5           dSP;
550             dMY_CXT;
551             int count, i;
552 5           int is_unicode = MY_CXT.last_dbh_is_unicode;
553 5           int rc = SQLITE_ERROR;
554             SV *rowidsv;
555              
556 5           ENTER;
557 5           SAVETMPS;
558              
559             /* call the _SQLITE_UPDATE() method */
560 5 50         PUSHMARK(SP);
561 5 50         XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj);
562 22 100         for(i = 0; i < argc; i++) {
563 17 50         XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], is_unicode));
564             }
565 5           PUTBACK;
566 5           count = call_method ("_SQLITE_UPDATE", G_SCALAR);
567 5           SPAGAIN;
568 5 50         if (count != 1) {
569 0           warn("cursor->_SQLITE_UPDATE() returned %d vals instead of 1", count);
570 0           SP -= count;
571             }
572             else {
573 5 50         if (argc > 1 && sqlite3_value_type(argv[0]) == SQLITE_NULL
    50          
574 5 50         && 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 5           rowidsv = POPs;
578 5 50         if (!SvOK(rowidsv))
    0          
    0          
579 0           *pRowid = 0;
580 5 50         else if (SvUOK(rowidsv))
581 0 0         *pRowid = SvUV(rowidsv);
582 5 50         else if (SvIOK(rowidsv))
583 5 50         *pRowid = SvIV(rowidsv);
584             else
585 0 0         *pRowid = (sqlite3_int64)SvNV(rowidsv);
586             }
587 5           rc = SQLITE_OK;
588             }
589              
590              
591 5           PUTBACK;
592 5 50         FREETMPS;
593 5           LEAVE;
594              
595 5           return rc;
596             }
597              
598 3           static int perl_vt_Begin(sqlite3_vtab *pVTab){
599 3           return _call_perl_vtab_method(pVTab, "BEGIN_TRANSACTION", 0);
600             }
601              
602 16           static int perl_vt_Sync(sqlite3_vtab *pVTab){
603 16           return _call_perl_vtab_method(pVTab, "SYNC_TRANSACTION", 0);
604             }
605              
606 16           static int perl_vt_Commit(sqlite3_vtab *pVTab){
607 16           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 13           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 13           dSP;
620             dMY_CXT;
621             int count;
622 13           int is_overloaded = 0;
623 13           char *func_name = sqlite3_mprintf("%s\t%d", zName, nArg);
624 13           STRLEN len = strlen(func_name);
625 13           HV *functions = ((perl_vtab *) pVTab)->functions;
626 13           SV* coderef = NULL;
627             SV** val;
628             SV *result;
629              
630 13           ENTER;
631 13           SAVETMPS;
632              
633             /* check if that function was already in cache */
634 13 100         if (hv_exists(functions, func_name, len)) {
635 6           val = hv_fetch(functions, func_name, len, FALSE);
636 6 50         if (val && SvOK(*val)) {
    100          
    50          
    50          
637 6           coderef = *val;
638             }
639             }
640             else {
641             /* call the FIND_FUNCTION() method */
642 7 50         PUSHMARK(SP);
643 7 50         XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj);
644 7 50         XPUSHs(sv_2mortal(newSViv(nArg)));
645 7 50         XPUSHs(sv_2mortal(newSVpv(zName, 0)));
646 7           PUTBACK;
647 7           count = call_method ("FIND_FUNCTION", G_SCALAR);
648 7           SPAGAIN;
649 7 50         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 7           result = POPs;
655 7 50         if (SvTRUE(result)) {
    50          
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    50          
    0          
    100          
656             /* the coderef must be valid for the lifetime of pVTab, so
657             make a copy */
658 4           coderef = newSVsv(result);
659             }
660              
661             /* store result in cache */
662 7 100         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 13 100         is_overloaded = coderef && SvTRUE(coderef);
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
667 13 100         if (is_overloaded) {
668 18           *pxFunc = MY_CXT.last_dbh_is_unicode ? sqlite_db_func_dispatcher_unicode
669 9 50         : sqlite_db_func_dispatcher_no_unicode;
670 9           *ppArg = coderef;
671             }
672              
673             cleanup:
674 13           PUTBACK;
675 13 100         FREETMPS;
676 13           LEAVE;
677 13           sqlite3_free(func_name);
678 13           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 11           sqlite_db_destroy_module_data(void *pAux)
755             {
756             dTHX;
757 11           dSP;
758             int count;
759 11           int rc = SQLITE_ERROR;
760             perl_vtab_init *init_data;
761              
762 11           ENTER;
763 11           SAVETMPS;
764              
765 11           init_data = (perl_vtab_init *)pAux;
766              
767             /* call the DESTROY_MODULE() method */
768 11 50         PUSHMARK(SP);
769 11 50         XPUSHs(sv_2mortal(newSVpv(init_data->perl_class, 0)));
770 11           PUTBACK;
771 11           count = call_method("DESTROY_MODULE", G_VOID);
772 11           SPAGAIN;
773 11           SP -= count;
774              
775             /* free module memory */
776 11           SvREFCNT_dec(init_data->dbh);
777 11           sqlite3_free((char *)init_data->perl_class);
778              
779 11           PUTBACK;
780 11 50         FREETMPS;
781 11           LEAVE;
782 11           }
783              
784              
785              
786             int
787 11           sqlite_db_create_module(pTHX_ SV *dbh, const char *name, const char *perl_class)
788             {
789 11           dSP;
790 11           D_imp_dbh(dbh);
791 11           int count, rc, retval = TRUE;
792             char *module_ISA;
793             char *loading_code;
794             perl_vtab_init *init_data;
795              
796 11           ENTER;
797 11           SAVETMPS;
798              
799 11 50         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 11           module_ISA = sqlite3_mprintf("%s::ISA", perl_class);
806 11 100         if (!get_av(module_ISA, 0)) {
807 5           loading_code = sqlite3_mprintf("use %s", perl_class);
808 5           eval_pv(loading_code, TRUE);
809 5           sqlite3_free(loading_code);
810             }
811 11           sqlite3_free(module_ISA);
812              
813             /* build the init datastructure that will be passed to perl_vt_New() */
814 11           init_data = sqlite3_malloc(sizeof(*init_data));
815 11           init_data->dbh = newRV(dbh);
816 11           sv_rvweaken(init_data->dbh);
817 11           init_data->perl_class = sqlite3_mprintf(perl_class);
818              
819             /* register within sqlite */
820 11           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 11 50         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 11 50         PUSHMARK(SP);
835 11 50         XPUSHs(sv_2mortal(newSVpv(perl_class, 0)));
836 11 50         XPUSHs(sv_2mortal(newSVpv(name, 0)));
837 11           PUTBACK;
838 11           count = call_method("CREATE_MODULE", G_VOID);
839 11           SPAGAIN;
840 11           SP -= count;
841              
842 11           PUTBACK;
843 11 50         FREETMPS;
844 11           LEAVE;
845              
846 11           return retval;
847             }