#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#define NEED_newRV_noinc
#define NEED_sv_2pv_nolen
#include "ppport.h"
#include "perlvtab.h"
SQLITE_EXTENSION_INIT1
#ifdef MULTIPLICITY
# define my_dTHX(a) pTHXx = ((PerlInterpreter*)((a) ? (a) : PERL_GET_THX))
#else
# define my_dTHX(a) dNOOP
#endif
#ifdef __APPLE__
extern char **environ;
#endif
typedef struct _perl_vtab {
sqlite3_vtab base;
SV *sv;
sqlite3 *db;
#ifdef MULTIPLICITY
PerlInterpreter *perl;
#endif
} perl_vtab;
typedef struct _perl_vtab_cursor {
sqlite3_vtab_cursor base;
SV *sv;
} perl_vtab_cursor;
#define VTM_CREATE 0
#define VTM_CONNECT 1
#define VTM_DROP 2
#define VTM_DISCONNECT 3
#define VTM_BEGIN_TRANSACTION 4
#define VTM_SYNC_TRANSACTION 5
#define VTM_COMMIT_TRANSACTION 6
#define VTM_ROLLBACK_TRANSACTION 7
EXTERN_C void xs_init (pTHX);
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
EXTERN_C void
xs_init(pTHX)
{
char *file = __FILE__;
dXSUB_SYS;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
}
static char *vtm_name[] = { "CREATE",
"CONNECT",
"DROP",
"DISCONNECT",
"BEGIN_TRANSACTION",
"SYNC_TRANSACTION",
"COMMIT_TRANSACTION",
"ROLLBACK_TRANSACTION",
NULL, };
static int
perlCreateOrConnect(sqlite3 *db,
void *pAux,
int argc, const char *const *argv,
sqlite3_vtab **ppVTab,
char **pzErr,
int method) {
my_dTHX(pAux);
dSP;
I32 ax;
int i;
int count;
SV *tmp;
perl_vtab *vtab = NULL;
SV *vtabsv;
int rc = SQLITE_OK;
if (argc < 4) {
Perl_warn(aTHX_ "Can't create virtual table, Perl driver name is missing");
return SQLITE_ERROR;
}
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv(VTAB_MODULE_LOADER, 0)));
XPUSHs(sv_2mortal(newSVpv(vtm_name[method], 0)));
for (i = 0; i<argc; i++) {
tmp = sv_2mortal(newSVpv(argv[i], 0));
SvUTF8_on(tmp);
XPUSHs(tmp);
}
PUTBACK;
count = call_method("_CREATE_OR_CONNECT", G_SCALAR|G_EVAL);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
PUTBACK;
vtabsv = ST(0);
if (!count || SvTRUE(ERRSV) || !SvOK(vtabsv)) {
Perl_warn(aTHX_ "%s::%s method failed: %s\n",
VTAB_MODULE_LOADER,
vtm_name[method],
SvTRUE(ERRSV) ? SvPV_nolen(ERRSV) : "method returned undef");
rc = SQLITE_ERROR;
goto cleanup;
}
PUSHMARK(SP);
XPUSHs(vtabsv);
PUTBACK;
count = call_method("DECLARE_SQL", G_SCALAR|G_EVAL);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
PUTBACK;
tmp = ST(0);
if (!count || SvTRUE(ERRSV) || !SvOK(tmp)) {
Perl_warn(aTHX_ "%s::DECLARE_SQL method failed: %s",
sv_reftype(SvRV(vtabsv), 1),
SvTRUE(ERRSV) ? SvPV_nolen(ERRSV) : "method returned undef");
rc = SQLITE_ERROR;
if (SvTRUE(ERRSV))
*pzErr = sqlite3_mprintf("%s", SvPV_nolen(ERRSV));
goto cleanup;
}
rc = sqlite3_declare_vtab(db, SvPVutf8_nolen(tmp));
if (rc != SQLITE_OK)
goto cleanup;
Newxz(vtab, 1, perl_vtab);
vtab->sv = SvREFCNT_inc(vtabsv);
vtab->db = db;
#ifdef MULTIPLICITY
vtab->perl = my_perl;
#endif
cleanup:
*ppVTab = (sqlite3_vtab *) vtab;
FREETMPS;
LEAVE;
return rc;
}
static int
perlCreate(sqlite3 *db,
void *pAux,
int argc, const char *const *argv,
sqlite3_vtab **ppVTab,
char **pzErr) {
return perlCreateOrConnect(db, pAux, argc, argv, ppVTab, pzErr, VTM_CREATE);
}
static int
perlConnect(sqlite3 *db,
void *pAux,
int argc, const char *const *argv,
sqlite3_vtab **ppVTab,
char **pzErr) {
return perlCreateOrConnect(db, pAux, argc, argv, ppVTab, pzErr, VTM_CONNECT);
}
static int
perlSimpleVtabMethod(sqlite3_vtab *vtab, int method) {
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
SV *vtabsv = ((perl_vtab*)vtab)->sv;
int count;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
PUTBACK;
count = call_method(vtm_name[method], G_VOID|G_EVAL);
SPAGAIN;
SP -= count;
PUTBACK;
if (SvTRUE(ERRSV)) {
Perl_warn(aTHX_ "%s::%s method failed: %s",
sv_reftype(SvRV(vtabsv), 1),
vtm_name[method],
SvPV_nolen(ERRSV));
rc = SQLITE_ERROR;
goto cleanup;
}
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static int
perlDropOrDisconnect(sqlite3_vtab *vtab, int method) {
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
SV *vtabsv = ((perl_vtab*)vtab)->sv;
int count;
int rc = SQLITE_OK;
assert(method < VTM__TOP);
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
PUTBACK;
count = call_method(vtm_name[method], G_VOID|G_EVAL);
SPAGAIN;
SP -= count;
PUTBACK;
if (SvTRUE(ERRSV)) {
Perl_warn(aTHX_ "%s::%s method failed: %s",
sv_reftype(SvRV(vtabsv), 1),
vtm_name[method],
SvPV_nolen(ERRSV));
rc = SQLITE_ERROR;
goto cleanup;
}
SvREFCNT_dec(vtabsv);
Safefree(vtab);
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static int
perlBegin(sqlite3_vtab *vtab) {
return perlSimpleVtabMethod(vtab, VTM_BEGIN_TRANSACTION);
}
static int
perlSync(sqlite3_vtab *vtab) {
return perlSimpleVtabMethod(vtab, VTM_SYNC_TRANSACTION);
}
static int
perlCommit(sqlite3_vtab *vtab) {
return perlSimpleVtabMethod(vtab, VTM_COMMIT_TRANSACTION);
}
static int
perlRollback(sqlite3_vtab *vtab) {
return perlSimpleVtabMethod(vtab, VTM_ROLLBACK_TRANSACTION);
}
static int
perlDestroy(sqlite3_vtab *vtab) {
return perlDropOrDisconnect(vtab, VTM_DROP);
}
static int
perlDisconnect(sqlite3_vtab *vtab) {
return perlDropOrDisconnect(vtab, VTM_DISCONNECT);
}
static int
perlOpen(sqlite3_vtab *vtab, sqlite3_vtab_cursor **ppCursor) {
my_dTHX(((perl_vtab *)vtab)->perl);
dSP;
I32 ax;
perl_vtab_cursor *cursor = NULL;
SV *vtabsv = ((perl_vtab*)vtab)->sv;
SV *cursv;
int count;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
PUTBACK;
count = call_method("OPEN", G_SCALAR|G_EVAL);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
PUTBACK;
cursv = ST(0);
if (!count || !SvOK(cursv)) {
Perl_warn(aTHX_ "%s::OPEN method failed: %s",
sv_reftype(SvRV(vtabsv), 1),
SvTRUE(ERRSV) ? SvPV_nolen(ERRSV) : "method returned undef");
rc = SQLITE_ERROR;
goto cleanup;
}
Newxz(cursor, 1, perl_vtab_cursor);
cursor->sv = SvREFCNT_inc(cursv);
SvREFCNT_inc(vtabsv);
cleanup:
*ppCursor = (sqlite3_vtab_cursor *) cursor;
FREETMPS;
LEAVE;
return rc;
}
static int
perlClose(sqlite3_vtab_cursor *cur) {
SV *cursv = ((perl_vtab_cursor *)cur)->sv;
perl_vtab *vtab = (perl_vtab *)(cur->pVtab);
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
SV *vtabsv = vtab->sv;
int count;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
XPUSHs(cursv);
PUTBACK;
count = call_method("CLOSE", G_VOID|G_EVAL);
SPAGAIN;
SP -= count;
PUTBACK;
if (SvTRUE(ERRSV)) {
Perl_warn(aTHX_ "%s::CLOSE method failed: %s", sv_reftype(SvRV(vtabsv), 1), SvPV_nolen(ERRSV));
rc = SQLITE_ERROR;
goto cleanup;
}
SvREFCNT_dec(cursv);
SvREFCNT_dec(vtabsv);
Safefree(cur);
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static char *
op2str(unsigned char op) {
switch (op) {
case SQLITE_INDEX_CONSTRAINT_EQ:
return "eq";
case SQLITE_INDEX_CONSTRAINT_GT:
return "gt";
case SQLITE_INDEX_CONSTRAINT_LE:
return "le";
case SQLITE_INDEX_CONSTRAINT_LT:
return "lt";
case SQLITE_INDEX_CONSTRAINT_GE:
return "ge";
case SQLITE_INDEX_CONSTRAINT_MATCH:
return "match";
default:
return "unknown";
}
}
int perlBestIndex(sqlite3_vtab *vtab, sqlite3_index_info *ixinfo) {
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
I32 ax;
SV *vtabsv = ((perl_vtab*)vtab)->sv;
AV *av;
AV *ctrain;
int count;
int i;
STRLEN len;
char *str;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
ctrain = newAV();
XPUSHs(sv_2mortal(newRV_noinc((SV*)ctrain)));
for (i = 0; i < ixinfo->nConstraint; i++) {
HV *hv = newHV();
av_push(ctrain, newRV_noinc((SV*)hv));
hv_store(hv, "column", 6, newSViv(ixinfo->aConstraint[i].iColumn), 0);
hv_store(hv, "operator", 8, newSVpv(op2str(ixinfo->aConstraint[i].op), 0), 0);
hv_store(hv, "usable", 6, (ixinfo->aConstraint[i].usable ? &PL_sv_yes : &PL_sv_no), 0);
}
av = newAV();
XPUSHs(sv_2mortal(newRV_noinc((SV*)av)));
for (i = 0; i < ixinfo->nOrderBy; i++) {
HV *hv = newHV();
av_push(av, newRV_noinc((SV*)hv));
hv_store(hv, "column", 6, newSViv(ixinfo->aOrderBy[i].iColumn), 0);
hv_store(hv, "direction", 9, newSViv(ixinfo->aOrderBy[i].desc ? -1 : 1), 0);
}
PUTBACK;
count = call_method("BEST_INDEX", G_ARRAY|G_EVAL);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
PUTBACK;
if (SvTRUE(ERRSV)) {
Perl_warn(aTHX_ "%s::BEST_INDEX method failed: %s\n", sv_reftype(SvRV(vtabsv), 1), SvPV_nolen(ERRSV));
rc = SQLITE_ERROR;
goto cleanup;
}
if (count != 4) {
Perl_warn(aTHX_ "%s::BEST_INDEX method returned wrong number of values (%d, %d expected)", sv_reftype(SvRV(vtabsv), 1), count, 4);
rc = SQLITE_ERROR;
goto cleanup;
}
ixinfo->idxNum = SvIV(ST(0));
str = SvPVutf8(ST(1), len);
ixinfo->idxStr = sqlite3_malloc(len+1);
memcpy(ixinfo->idxStr, str, len);
ixinfo->idxStr[len] = 0;
ixinfo->needToFreeIdxStr = 1;
ixinfo->orderByConsumed = SvTRUE(ST(2));
ixinfo->estimatedCost = SvNV(ST(3));
for (i = 0; i < ixinfo->nConstraint; i++) {
SV **rv = av_fetch(ctrain, i, FALSE);
if (rv && SvROK(*rv) && SvTYPE(SvRV(*rv)) == SVt_PVHV) {
HV *hv = (HV*)SvRV(*rv);
SV **val;
val = hv_fetch(hv, "arg_index", 9, FALSE);
ixinfo->aConstraintUsage[i].argvIndex = (val && SvOK(*val)) ? SvIV(*val) + 1 : 0;
val = hv_fetch(hv, "omit", 4, FALSE);
ixinfo->aConstraintUsage[i].omit = (val && SvTRUE(*val)) ? 1 : 0;
/* Perl_warn(aTHX_ "omit: %d\n", ixinfo->aConstraintUsage[i].omit); */
}
else {
Perl_warn(aTHX_ "%s::BEST_INDEX method has corrupted constraint data structure",
sv_reftype(SvRV(vtabsv), 1));
rc = SQLITE_ERROR;
goto cleanup;
}
}
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static int
perlEof(sqlite3_vtab_cursor* cur) {
I32 ax;
SV *cursv = ((perl_vtab_cursor *)cur)->sv;
perl_vtab *vtab = (perl_vtab *)(cur->pVtab);
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
SV *vtabsv = vtab->sv;
SV *rcsv;
int count;
int rc = 0;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
XPUSHs(cursv);
PUTBACK;
count = call_method("EOF", G_SCALAR|G_EVAL);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
rcsv = ST(0);
PUTBACK;
if (SvTRUE(ERRSV)) {
Perl_warn(aTHX_ "%s::EOF method failed: %s", sv_reftype(SvRV(vtabsv), 1), SvPV_nolen(ERRSV));
rc = 1;
goto cleanup;
}
rc = SvTRUE(rcsv);
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static int
perlNext(sqlite3_vtab_cursor* cur) {
SV *cursv = ((perl_vtab_cursor *)cur)->sv;
perl_vtab *vtab = (perl_vtab *)(cur->pVtab);
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
SV *vtabsv = vtab->sv;
SV *rcsv;
int count;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
XPUSHs(cursv);
PUTBACK;
count = call_method("NEXT", G_SCALAR|G_EVAL);
SPAGAIN;
SP -= count;
PUTBACK;
if (SvTRUE(ERRSV)) {
Perl_warn(aTHX_ "%s::NEXT method failed: %s", sv_reftype(SvRV(vtabsv), 1), SvPV_nolen(ERRSV));
rc = SQLITE_ERROR;
}
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static int
perlColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int n) {
I32 ax;
SV *cursv = ((perl_vtab_cursor *)cur)->sv;
perl_vtab *vtab = (perl_vtab *)(cur->pVtab);
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
SV *vtabsv = vtab->sv;
SV *sv;
int count;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
XPUSHs(cursv);
XPUSHs(sv_2mortal(newSViv(n)));
PUTBACK;
count = call_method("COLUMN", G_SCALAR|G_EVAL);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
PUTBACK;
sv = ST(0);
if (SvTRUE(ERRSV)) {
STRLEN len;
char *str;
SV *err = sv_2mortal(newSVpvf("%s::COLUMN method failed: %s", sv_reftype(SvRV(vtabsv), 1), SvPV_nolen(ERRSV)));
str = SvPVutf8(err, len);
sqlite3_result_error(ctx, str, len);
rc = SQLITE_ERROR;
goto cleanup;
}
if (!SvOK(sv)) {
/* Perl_warn(aTHX_ "undef found"); */
sqlite3_result_null(ctx);
}
else if (SvIOK(sv)) {
/* Perl_warn(aTHX_ "int found"); */
sqlite3_result_int(ctx, SvIV(sv));
}
else if (SvNOK(sv)) {
/* Perl_warn(aTHX_ "number found"); */
sqlite3_result_double(ctx, SvNV(sv));
}
else {
STRLEN len;
char *str = SvPVutf8(sv, len);
/* Perl_warn(aTHX_ "string found"); */
sqlite3_result_text(ctx, str, len, SQLITE_TRANSIENT);
}
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static SV *
newSVsqlite3_value(pTHX_ sqlite3_value *v) {
SV *sv;
int type = sqlite3_value_type(v);
switch(type) {
case SQLITE_NULL:
return &PL_sv_undef;
case SQLITE_INTEGER:
return newSViv(sqlite3_value_int(v));
case SQLITE_FLOAT:
return newSVnv(sqlite3_value_double(v));
case SQLITE_TEXT:
sv = newSVpvn(sqlite3_value_text(v),
sqlite3_value_bytes(v));
SvUTF8_on(sv);
return sv;
case SQLITE_BLOB:
return newSVpvn((char *)sqlite3_value_text(v),
sqlite3_value_bytes(v));
}
Perl_warn(aTHX_ "unsupported SQLite type %d found", type);
return &PL_sv_undef;
}
static int
perlFilter(sqlite3_vtab_cursor *cur,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv) {
SV *cursv = ((perl_vtab_cursor *)cur)->sv;
perl_vtab *vtab = (perl_vtab *)(cur->pVtab);
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
SV *vtabsv = vtab->sv;
SV *tmp;
int i;
int count;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
XPUSHs(cursv);
XPUSHs(sv_2mortal(newSViv(idxNum)));
tmp = sv_2mortal(newSVpv(idxStr, 0));
SvUTF8_on(tmp);
XPUSHs(tmp);
for (i = 0; i < argc; i++)
XPUSHs(sv_2mortal(newSVsqlite3_value(aTHX_ argv[i])));
PUTBACK;
count = call_method("FILTER", G_VOID|G_EVAL);
SPAGAIN;
SP -= count;
PUTBACK;
if (SvTRUE(ERRSV)) {
Perl_warn(aTHX_ "%s::FILTER method failed: %s", sv_reftype(SvRV(vtabsv), 1), SvPV_nolen(ERRSV));
rc = SQLITE_ERROR;
}
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static int
perlRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *rowid) {
SV *cursv = ((perl_vtab_cursor *)cur)->sv;
perl_vtab *vtab = (perl_vtab *)(cur->pVtab);
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
SV *vtabsv = vtab->sv;
SV *rowidsv;
I32 ax;
int i;
int count;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
XPUSHs(cursv);
PUTBACK;
count = call_method("ROWID", G_SCALAR|G_EVAL);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
PUTBACK;
rowidsv = ST(0);
if (!count || SvTRUE(ERRSV) || !SvOK(rowidsv)) {
Perl_warn(aTHX_ "%s::ROWID method failed: %s",
sv_reftype(SvRV(vtabsv), 1),
SvTRUE(ERRSV) ? SvPV_nolen(ERRSV) : "method returned undef");
rc = SQLITE_ERROR;
goto cleanup;
}
if (SvUOK(rowidsv))
*rowid = SvUV(rowidsv);
else if (SvIOK(rowidsv))
*rowid = SvIV(rowidsv);
else
*rowid = SvNV(rowidsv);
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static int
perlUpdate(sqlite3_vtab *vtab, int argc, sqlite3_value **argv, sqlite_int64 *rowid) {
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
I32 ax;
SV *vtabsv = ((perl_vtab*)vtab)->sv;
SV *rowidsv;
int i;
int count;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
for (i = 0; i < argc; i++)
XPUSHs(sv_2mortal(newSVsqlite3_value(aTHX_ argv[i])));
PUTBACK;
count = call_method("UPDATE", G_SCALAR|G_EVAL);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
PUTBACK;
if (!count || SvTRUE(ERRSV)) {
Perl_warn(aTHX_ "%s::UPDATE method failed: %s\n",
sv_reftype(SvRV(vtabsv), 1),
SvPV_nolen(ERRSV));
rc = SQLITE_ERROR;
goto cleanup;
}
rowidsv = ST(0);
if (!SvOK(rowidsv))
*rowid = 0;
else if (SvUOK(rowidsv))
*rowid = SvUV(rowidsv);
else if (SvIOK(rowidsv))
*rowid = SvIV(rowidsv);
else
*rowid = SvNV(rowidsv);
cleanup:
FREETMPS;
LEAVE;
return rc;
}
static int
perlRename(sqlite3_vtab *vtab, const char *name) {
my_dTHX(((perl_vtab*)vtab)->perl);
dSP;
I32 ax;
SV *vtabsv = ((perl_vtab*)vtab)->sv;
int count;
int rc = SQLITE_OK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(vtabsv);
XPUSHs(sv_2mortal(newSVpv(name, 0)));
PUTBACK;
count = call_method("RENAME", G_SCALAR|G_EVAL);
SPAGAIN;
SP -= count;
ax = (SP - PL_stack_base) + 1;
PUTBACK;
if (!count || SvTRUE(ERRSV)) {
Perl_warn(aTHX_ "%s::RENAME method failed: %s\n",
sv_reftype(SvRV(vtabsv), 1),
SvPV_nolen(ERRSV));
rc = SQLITE_ERROR;
goto cleanup;
}
rc = (SvTRUE(ST(0)) ? SQLITE_OK : SQLITE_ERROR);
cleanup:
FREETMPS;
LEAVE;
return rc;
}
sqlite3_module vtab_perl_module = {
1,
perlCreate,
perlConnect,
perlBestIndex,
perlDisconnect,
perlDestroy,
perlOpen,
perlClose,
perlFilter,
perlNext,
perlEof,
perlColumn,
perlRowid,
perlUpdate,
perlBegin,
perlSync,
perlCommit,
perlRollback,
NULL, /* perlFindFunction - not implemented yet! */
perlRename,
};
static char *argv[] = { "perlvtab",
"-e",
"$SQLite::VirtualTable::EMBEDED=1;"
"require SQLite::VirtualTable",
NULL };
int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg,
const sqlite3_api_routines *pApi) {
PerlInterpreter *my_perl = perl_alloc();
int ac = 3;
char **av = argv;
char **env = environ;
PERL_SYS_INIT3(&ac, &av, &env);
perl_construct(my_perl);
perl_parse(my_perl, xs_init, ac, av, env);
perl_run(my_perl);
SQLITE_EXTENSION_INIT2(pApi)
sqlite3_create_module(db, "perl", &vtab_perl_module, my_perl);
return SQLITE_OK;
}
int dbd_sqlite_init_vtab_extension(sqlite3 *db, char **pzErrMsg,
const sqlite3_api_routines *pApi) {
SQLITE_EXTENSION_INIT2(pApi)
sqlite3_create_module(db, "perl", &vtab_perl_module, NULL);
return SQLITE_OK;
}