File Coverage

dbdimp_virtual_table.inc
Criterion Covered Total %
statement 388 462 83.9
branch 199 494 40.2
condition n/a
subroutine n/a
pod n/a
total 587 956 61.4


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