00001
00018 #if defined(_WIN32) || defined(_WIN64)
00019 #include <windows.h>
00020 #endif
00021 #include <stdio.h>
00022 #include <string.h>
00023 #include <ctype.h>
00024 #include <stdlib.h>
00025 #include <libxml/parser.h>
00026 #include <libxml/tree.h>
00027 #include <libxml/xpath.h>
00028 #ifdef WITH_XSLT
00029 #include <libxslt/xslt.h>
00030 #include <libxslt/transform.h>
00031 #include <libxslt/xsltutils.h>
00032 #endif
00033
00034 #ifdef STANDALONE
00035 #include <sqlite3.h>
00036 #else
00037 #include <sqlite3ext.h>
00038 static SQLITE_EXTENSION_INIT1
00039 #endif
00040
00047 typedef struct XDOC {
00048 xmlDocPtr doc;
00049 int refcnt;
00050 } XDOC;
00051
00058 typedef struct XMOD {
00059 int refcnt;
00060 sqlite3_mutex *mutex;
00061 int sdoc;
00062 int ndoc;
00063 XDOC *docs;
00064 } XMOD;
00065
00066 static int initialized = 0;
00067 static XMOD *xmod = 0;
00068
00075 typedef struct XTAB {
00076 sqlite3_vtab vtab;
00077 sqlite3 *db;
00078 XMOD *xm;
00079 struct XCSR *xc;
00080 int sdoc;
00081 int ndoc;
00082 int *idocs;
00083 } XTAB;
00084
00091 typedef struct XEXP {
00092 struct XEXP *next;
00093 struct XEXP *prev;
00094 xmlDocPtr doc;
00095 xmlXPathContextPtr pctx;
00096 xmlXPathObjectPtr pobj;
00097 xmlNodePtr parent;
00098 int pos;
00099 int conv;
00100 char expr[1];
00101 } XEXP;
00102
00109 typedef struct XCSR {
00110 sqlite3_vtab_cursor cursor;
00111 int pos;
00112 int nexpr;
00113 XEXP *first;
00114 XEXP *last;
00115 } XCSR;
00116
00134 static int
00135 xpath_connect(sqlite3* db, void *aux, int argc, const char * const *argv,
00136 sqlite3_vtab **vtabp, char **errp)
00137 {
00138 int rc = SQLITE_ERROR;
00139 XTAB *xt;
00140
00141 xt = sqlite3_malloc(sizeof (XTAB));
00142 if (!xt) {
00143 nomem:
00144 *errp = sqlite3_mprintf("out of memory");
00145 return rc;
00146 }
00147 memset(xt, 0, sizeof (XTAB));
00148 xt->db = db;
00149 xt->xm = (XMOD *) aux;
00150 xt->xc = 0;
00151 xt->sdoc = 128;
00152 xt->ndoc = 0;
00153 xt->idocs = sqlite3_malloc(xt->sdoc * sizeof (int));
00154 if (!xt->idocs) {
00155 sqlite3_free(xt);
00156 goto nomem;
00157 }
00158 rc = sqlite3_declare_vtab(db,
00159 "CREATE TABLE x("
00160 " DOCID INTEGER PRIMARY KEY,"
00161 " XML HIDDEN BLOB,"
00162 " PATH HIDDEN TEXT,"
00163 " OPTIONS HIDDEN INTEGER,"
00164 " ENCODING HIDDEN TEXT,"
00165 " BASEURL HIDDEN TEXT,"
00166 " XMLDUMP HIDDEN TEXT"
00167 ")");
00168 if (rc != SQLITE_OK) {
00169 sqlite3_free(xt->idocs);
00170 sqlite3_free(xt);
00171 *errp = sqlite3_mprintf("table definition failed (error %d)", rc);
00172 return rc;
00173 }
00174 *vtabp = &xt->vtab;
00175 *errp = 0;
00176 return SQLITE_OK;
00177 }
00178
00190 static int
00191 xpath_create(sqlite3* db, void *aux, int argc,
00192 const char *const *argv,
00193 sqlite3_vtab **vtabp, char **errp)
00194 {
00195 return xpath_connect(db, aux, argc, argv, vtabp, errp);
00196 }
00197
00204 static int
00205 xpath_disconnect(sqlite3_vtab *vtab)
00206 {
00207 XTAB *xt = (XTAB *) vtab;
00208 XMOD *xm = xt->xm;
00209 int i, n;
00210
00211 if (xm->mutex) {
00212 sqlite3_mutex_enter(xm->mutex);
00213 for (i = 0; xm->docs && (i < xt->ndoc); i++) {
00214 n = xt->idocs[i];
00215 if ((n >= 0) && (n < xm->sdoc)) {
00216 xmlDocPtr doc = xm->docs[n].doc;
00217 if (doc) {
00218 xm->docs[n].refcnt -= 1;
00219 if (xm->docs[n].refcnt <= 0) {
00220 xm->docs[n].doc = 0;
00221 xm->docs[n].refcnt = 0;
00222 xm->ndoc--;
00223 xmlFreeDoc(doc);
00224 }
00225 }
00226 }
00227 }
00228 sqlite3_mutex_leave(xm->mutex);
00229 }
00230 sqlite3_free(xt->idocs);
00231 sqlite3_free(xt);
00232 return SQLITE_OK;
00233 }
00234
00241 static int
00242 xpath_destroy(sqlite3_vtab *vtab)
00243 {
00244 return xpath_disconnect(vtab);
00245 }
00246
00254 static int
00255 xpath_bestindex(sqlite3_vtab *vtab, sqlite3_index_info *info)
00256 {
00257 return SQLITE_OK;
00258 }
00259
00267 static int
00268 xpath_open(sqlite3_vtab *vtab, sqlite3_vtab_cursor **cursorp)
00269 {
00270 XCSR *xc = sqlite3_malloc(sizeof (XCSR));
00271
00272 if (!xc) {
00273 return SQLITE_ERROR;
00274 }
00275 xc->cursor.pVtab = vtab;
00276 xc->pos = -1;
00277 xc->nexpr = 0;
00278 xc->first = xc->last = 0;
00279 *cursorp = &xc->cursor;
00280 return SQLITE_OK;
00281 }
00282
00289 static int
00290 xpath_close(sqlite3_vtab_cursor *cursor)
00291 {
00292 XCSR *xc = (XCSR *) cursor;
00293 XEXP *xp = xc->first, *next;
00294 XTAB *xt = (XTAB *) xc->cursor.pVtab;
00295
00296 while (xp) {
00297 next = xp->next;
00298 if (xp->pobj) {
00299 xmlXPathFreeObject(xp->pobj);
00300 }
00301 if (xp->pctx) {
00302 xmlXPathFreeContext(xp->pctx);
00303 }
00304 sqlite3_free(xp);
00305 xp = next;
00306 }
00307 if (xt->xc == xc) {
00308 xt->xc = 0;
00309 }
00310 sqlite3_free(xc);
00311 return SQLITE_OK;
00312 }
00313
00320 static int
00321 xpath_next(sqlite3_vtab_cursor *cursor)
00322 {
00323 XCSR *xc = (XCSR *) cursor;
00324 XTAB *xt = (XTAB *) xc->cursor.pVtab;
00325 XEXP *xp;
00326
00327 if (xc->pos < xt->ndoc) {
00328 int ninc = 0;
00329
00330 if ((xc->pos >= 0) && xc->nexpr) {
00331 int newpos;
00332 xmlNodePtr node, parent = 0;
00333
00334 xp = xc->first;
00335 while (xp) {
00336 if (xp->pobj) {
00337 if (xp == xc->first) {
00338 parent = xp->parent;
00339 } else if (parent != xp->parent) {
00340 break;
00341 }
00342 }
00343 xp = xp->next;
00344 }
00345 if (parent && !xp) {
00346 int pchg = 0;
00347
00348 xp = xc->first;
00349 while (xp) {
00350 if (xp->pobj && (xp->pobj->type == XPATH_NODESET) &&
00351 xp->pobj->nodesetval) {
00352 newpos = xp->pos + 1;
00353 if (newpos < xp->pobj->nodesetval->nodeNr) {
00354 node = xp->pobj->nodesetval->nodeTab[newpos];
00355 if (node->parent != xp->parent) {
00356 pchg++;
00357 }
00358 } else {
00359 pchg++;
00360 }
00361 }
00362 xp = xp->next;
00363 }
00364 if ((pchg != 0) && (pchg != xc->nexpr)) {
00365 xp = xc->first;
00366 while (xp) {
00367 if (xp->pobj && (xp->pobj->type == XPATH_NODESET) &&
00368 xp->pobj->nodesetval) {
00369 newpos = xp->pos + 1;
00370 if (newpos < xp->pobj->nodesetval->nodeNr) {
00371 node = xp->pobj->nodesetval->nodeTab[newpos];
00372 if (node->parent == xp->parent) {
00373 xp->pos = newpos;
00374 ninc++;
00375 }
00376 } else {
00377 xp->pos = xp->pobj->nodesetval->nodeNr;
00378 ninc++;
00379 }
00380 }
00381 xp = xp->next;
00382 }
00383 }
00384 }
00385 if (!ninc) {
00386 xp = xc->first;
00387 while (xp) {
00388 if (xp->pobj && (xp->pobj->type == XPATH_NODESET) &&
00389 xp->pobj->nodesetval) {
00390 newpos = xp->pos + 1;
00391 if (newpos < xp->pobj->nodesetval->nodeNr) {
00392 xp->pos = newpos;
00393 ninc++;
00394 } else {
00395 xp->pos = xp->pobj->nodesetval->nodeNr;
00396 }
00397 }
00398 xp = xp->next;
00399 }
00400 }
00401 }
00402 if (!ninc) {
00403 xc->pos++;
00404 xp = xc->first;
00405 while (xp) {
00406 xp->pos = -1;
00407 xp->parent = 0;
00408 xp = xp->next;
00409 }
00410 }
00411 }
00412 return SQLITE_OK;
00413 }
00414
00425 static int
00426 xpath_filter(sqlite3_vtab_cursor *cursor, int idxNum,
00427 const char *idxStr, int argc, sqlite3_value **argv)
00428 {
00429 XCSR *xc = (XCSR *) cursor;
00430 XTAB *xt = (XTAB *) xc->cursor.pVtab;
00431
00432 xc->pos = -1;
00433 xt->xc = xc;
00434 return xpath_next(cursor);
00435 }
00436
00443 static int
00444 xpath_eof(sqlite3_vtab_cursor *cursor)
00445 {
00446 XCSR *xc = (XCSR *) cursor;
00447 XTAB *xt = (XTAB *) xc->cursor.pVtab;
00448
00449 return xc->pos >= xt->ndoc;
00450 }
00451
00460 static int
00461 xpath_column(sqlite3_vtab_cursor *cursor, sqlite3_context *ctx, int n)
00462 {
00463 XCSR *xc = (XCSR *) cursor;
00464 XTAB *xt = (XTAB *) xc->cursor.pVtab;
00465 XMOD *xm = (XMOD *) xt->xm;
00466
00467 if ((xc->pos < 0) || (xc->pos >= xt->ndoc)) {
00468 sqlite3_result_error(ctx, "column out of bounds", -1);
00469 return SQLITE_ERROR;
00470 }
00471 if (n == 0) {
00472 n = xt->idocs[xc->pos];
00473 if (xm->docs[n].doc) {
00474 sqlite3_result_int(ctx, n + 1);
00475 return SQLITE_OK;
00476 }
00477 } else if (n == 6) {
00478 n = xt->idocs[xc->pos];
00479 if (xm->docs[n].doc) {
00480 xmlChar *dump = 0;
00481 int dump_len = 0;
00482
00483 xmlDocDumpFormatMemoryEnc(xm->docs[n].doc, &dump,
00484 &dump_len, "utf-8", 1);
00485 if (dump) {
00486 sqlite3_result_text(ctx, (char *) dump, dump_len,
00487 SQLITE_TRANSIENT);
00488 xmlFree(dump);
00489 return SQLITE_OK;
00490 }
00491 }
00492 }
00493 sqlite3_result_null(ctx);
00494 return SQLITE_OK;
00495 }
00496
00504 static int
00505 xpath_rowid(sqlite3_vtab_cursor *cursor, sqlite3_int64 *rowidp)
00506 {
00507 XCSR *xc = (XCSR *) cursor;
00508 XTAB *xt = (XTAB *) xc->cursor.pVtab;
00509 XMOD *xm = (XMOD *) xt->xm;
00510 int n = xt->idocs[xc->pos];
00511
00512 if (xm->docs[n].doc) {
00513 *rowidp = (sqlite3_int64) (n + 1);
00514 return SQLITE_OK;
00515 }
00516 return SQLITE_ERROR;
00517 }
00518
00549 static int
00550 xpath_update(sqlite3_vtab *vtab, int argc, sqlite3_value **argv,
00551 sqlite3_int64 *rowidp)
00552 {
00553 int n = -1, rc = SQLITE_ERROR;
00554 XTAB *xt = (XTAB *) vtab;
00555 XMOD *xm = (XMOD *) xt->xm;
00556 xmlDocPtr doc = 0, docToFree = 0;
00557
00558 if (argc == 1) {
00559
00560 int i, k = -1;
00561
00562 n = sqlite3_value_int(argv[0]);
00563 for (i = 0; i < xt->ndoc; i++) {
00564 if ((n - 1) == xt->idocs[i]) {
00565 k = xt->idocs[i];
00566 memmove(xt->idocs + i, xt->idocs + i + 1,
00567 (xt->ndoc - (i + 1)) * sizeof (int));
00568 xt->ndoc--;
00569 break;
00570 }
00571 }
00572 if ((k >= 0) && xm->mutex) {
00573 n = k;
00574 doc = xm->docs[n].doc;
00575 }
00576 rc = SQLITE_OK;
00577 } else if ((argc > 1) && (sqlite3_value_type(argv[0]) == SQLITE_NULL)) {
00578
00579 int i, docid;
00580 int opts = (XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
00581 char *enc = 0;
00582
00583 if (sqlite3_value_type(argv[1]) != SQLITE_NULL) {
00584 if (vtab->zErrMsg) {
00585 sqlite3_free(vtab->zErrMsg);
00586 }
00587 vtab->zErrMsg = sqlite3_mprintf("ROWID must be NULL");
00588 rc = SQLITE_CONSTRAINT;
00589 goto done;
00590 }
00591 if (sqlite3_value_type(argv[2]) != SQLITE_NULL) {
00592 docid = sqlite3_value_int(argv[2]);
00593 if ((sqlite3_value_type(argv[3]) != SQLITE_NULL) ||
00594 (sqlite3_value_type(argv[4]) != SQLITE_NULL)) {
00595 if (vtab->zErrMsg) {
00596 sqlite3_free(vtab->zErrMsg);
00597 }
00598 vtab->zErrMsg = sqlite3_mprintf("XML and PATH must be NULL");
00599 rc = SQLITE_CONSTRAINT;
00600 goto done;
00601 }
00602 sqlite3_mutex_enter(xm->mutex);
00603 for (i = 0; xm->docs && (i < xt->ndoc); i++) {
00604 if ((docid - 1) == xt->idocs[i]) {
00605 sqlite3_mutex_leave(xm->mutex);
00606 if (vtab->zErrMsg) {
00607 sqlite3_free(vtab->zErrMsg);
00608 }
00609 vtab->zErrMsg = sqlite3_mprintf("constraint violation");
00610 rc = SQLITE_CONSTRAINT;
00611 goto done;
00612 }
00613 }
00614 if ((docid > 0) && (docid <= xm->sdoc)) {
00615 doc = xm->docs[docid - 1].doc;
00616 if (doc) {
00617 xm->docs[docid - 1].refcnt++;
00618 }
00619 }
00620 sqlite3_mutex_leave(xm->mutex);
00621 if (!doc) {
00622 if (vtab->zErrMsg) {
00623 sqlite3_free(vtab->zErrMsg);
00624 }
00625 vtab->zErrMsg = sqlite3_mprintf("invalid DOCID");
00626 goto done;
00627 }
00628 goto havedoc;
00629 }
00630 if (((sqlite3_value_type(argv[3]) == SQLITE_NULL) &&
00631 (sqlite3_value_type(argv[4]) == SQLITE_NULL)) ||
00632 ((sqlite3_value_type(argv[3]) != SQLITE_NULL) &&
00633 (sqlite3_value_type(argv[4]) != SQLITE_NULL))) {
00634 if (vtab->zErrMsg) {
00635 sqlite3_free(vtab->zErrMsg);
00636 }
00637 vtab->zErrMsg = sqlite3_mprintf("specify one of XML or PATH");
00638 rc = SQLITE_CONSTRAINT;
00639 goto done;
00640 }
00641 if (sqlite3_value_type(argv[5]) != SQLITE_NULL) {
00642 opts = sqlite3_value_int(argv[5]);
00643 }
00644 if (sqlite3_value_type(argv[6]) != SQLITE_NULL) {
00645 enc = (char *) sqlite3_value_text(argv[6]);
00646 }
00647 if (sqlite3_value_type(argv[4]) != SQLITE_NULL) {
00648 doc = xmlReadFile((char *) sqlite3_value_text(argv[4]), enc, opts);
00649 } else {
00650 char *url = 0;
00651
00652 if (sqlite3_value_type(argv[7]) != SQLITE_NULL) {
00653 url = (char *) sqlite3_value_text(argv[7]);
00654 }
00655 doc = xmlReadMemory(sqlite3_value_blob(argv[3]),
00656 sqlite3_value_bytes(argv[3]),
00657 url ? url : "", enc, opts);
00658 }
00659 if (!doc) {
00660 if (vtab->zErrMsg) {
00661 sqlite3_free(vtab->zErrMsg);
00662 }
00663 vtab->zErrMsg = sqlite3_mprintf("read error");
00664 goto done;
00665 }
00666 docToFree = doc;
00667 havedoc:
00668 if (xt->ndoc >= xt->sdoc) {
00669 int *idocs = sqlite3_realloc(xt->idocs, xt->sdoc +
00670 128 * sizeof (int));
00671
00672 if (!idocs) {
00673 goto nomem;
00674 }
00675 xt->idocs = idocs;
00676 xt->sdoc += 128;
00677 }
00678 if (!xm->mutex) {
00679 goto nomem;
00680 }
00681 sqlite3_mutex_enter(xm->mutex);
00682 if (xm->ndoc >= xt->sdoc) {
00683 XDOC *docs = sqlite3_realloc(xm->docs, xt->sdoc +
00684 128 * sizeof (XDOC));
00685
00686 if (!docs) {
00687 sqlite3_mutex_leave(xm->mutex);
00688 goto nomem;
00689 }
00690 xm->docs = docs;
00691 docs += xt->sdoc;
00692 memset(docs, 0, 128 * sizeof (XDOC));
00693 xt->sdoc += 128;
00694 }
00695 for (i = 0; i < xm->sdoc; i++) {
00696 if (!xm->docs[i].doc) {
00697 xm->docs[i].doc = doc;
00698 xm->docs[i].refcnt = 1;
00699 xm->ndoc++;
00700 xt->idocs[xt->ndoc++] = i;
00701 *rowidp = (sqlite3_int64) (i + 1);
00702 doc = docToFree = 0;
00703 rc = SQLITE_OK;
00704 break;
00705 }
00706 }
00707 sqlite3_mutex_leave(xm->mutex);
00708 } else {
00709
00710 if (vtab->zErrMsg) {
00711 sqlite3_free(vtab->zErrMsg);
00712 }
00713 vtab->zErrMsg = sqlite3_mprintf("UPDATE not supported");
00714 }
00715 done:
00716 if (docToFree) {
00717 xmlFreeDoc(docToFree);
00718 } else if (doc && (n >= 0)) {
00719 sqlite3_mutex_enter(xm->mutex);
00720 xm->docs[n].refcnt -= 1;
00721 if (xm->docs[n].refcnt <= 0) {
00722 xm->docs[n].doc = 0;
00723 xm->docs[n].refcnt = 0;
00724 xm->ndoc--;
00725 xmlFreeDoc(doc);
00726 }
00727 sqlite3_mutex_leave(xm->mutex);
00728 }
00729 return rc;
00730 nomem:
00731 if (vtab->zErrMsg) {
00732 sqlite3_free(vtab->zErrMsg);
00733 }
00734 vtab->zErrMsg = sqlite3_mprintf("out of memory");
00735 rc = SQLITE_NOMEM;
00736 goto done;
00737 }
00738
00756 static void
00757 xpath_vfunc_common(sqlite3_context *ctx, int conv, int argc,
00758 sqlite3_value **argv)
00759 {
00760 XTAB *xt = (XTAB *) sqlite3_user_data(ctx);
00761 XMOD *xm = xt->xm;
00762 XCSR *xc = xt->xc;
00763 XEXP *xp;
00764 xmlXPathContextPtr pctx = 0;
00765 xmlXPathObjectPtr pobj = 0;
00766 int n;
00767 char *p;
00768
00769 if ((argc < 2) || !sqlite3_value_text(argv[1])) {
00770 sqlite3_result_error(ctx, "wrong arguments", -1);
00771 goto done;
00772 }
00773 if (!xc) {
00774 sqlite3_result_error(ctx, "not in virtual table context", -1);
00775 goto done;
00776 }
00777 if ((xc->pos < 0) || (xc->pos >= xt->ndoc)) {
00778 sqlite3_result_error(ctx, "cursor out of bounds", -1);
00779 goto done;
00780 }
00781 n = xt->idocs[xc->pos];
00782 if (!xm->docs[n].doc) {
00783 sqlite3_result_error(ctx, "no docid", -1);
00784 goto done;
00785 }
00786 p = (char *) sqlite3_value_text(argv[1]);
00787 if (!p || !p[0]) {
00788 sqlite3_result_error(ctx, "no or empty XPath expression", -1);
00789 goto done;
00790 }
00791 xp = xc->first;
00792 while (xp) {
00793 if (!strcmp(p, xp->expr)) {
00794 break;
00795 }
00796 xp = xp->next;
00797 }
00798 if (!xp) {
00799 xp = sqlite3_malloc(sizeof (XEXP) + strlen(p));
00800 if (!xp) {
00801 sqlite3_result_error(ctx, "out of memory", -1);
00802 goto done;
00803 }
00804 xp->next = xp->prev = 0;
00805 strcpy(xp->expr, p);
00806 pctx = xmlXPathNewContext(xm->docs[n].doc);
00807 if (!pctx) {
00808 sqlite3_free(xp);
00809 sqlite3_result_error(ctx, "out of memory", -1);
00810 goto done;
00811 }
00812 pobj = xmlXPathEvalExpression((xmlChar *) xp->expr, pctx);
00813 if (!pobj) {
00814 sqlite3_free(xp);
00815 sqlite3_result_error(ctx, "bad XPath expression", -1);
00816 goto done;
00817 }
00818 xp->doc = xm->docs[n].doc;
00819 xp->pctx = pctx;
00820 xp->pobj = pobj;
00821 xp->parent = 0;
00822 xp->pos = -1;
00823 xp->conv = conv;
00824 pctx = 0;
00825 pobj = 0;
00826 xc->nexpr++;
00827 if (xc->first) {
00828 xc->last->next = xp;
00829 xp->prev = xc->last;
00830 xc->last = xp;
00831 } else {
00832 xc->first = xc->last = xp;
00833 }
00834 } else if (xm->docs[n].doc != xp->doc) {
00835 if (xp->pobj) {
00836 xmlXPathFreeObject(xp->pobj);
00837 xp->pobj = 0;
00838 }
00839 if (xp->pctx) {
00840 xmlXPathFreeContext(xp->pctx);
00841 xp->pctx = 0;
00842 }
00843 xp->doc = xm->docs[n].doc;
00844 xp->parent = 0;
00845 xp->pos = -1;
00846 if (xp->doc) {
00847 pctx = xmlXPathNewContext(xm->docs[n].doc);
00848 if (!pctx) {
00849 sqlite3_result_error(ctx, "out of memory", -1);
00850 goto done;
00851 }
00852 pobj = xmlXPathEvalExpression((xmlChar *) xp->expr, pctx);
00853 if (!pobj) {
00854 sqlite3_result_error(ctx, "bad XPath expression", -1);
00855 goto done;
00856 }
00857 xp->pctx = pctx;
00858 xp->pobj = pobj;
00859 pctx = 0;
00860 pobj = 0;
00861 }
00862 }
00863 if (xp->pos < 0) {
00864 xp->pos = 0;
00865 }
00866 if (!xp->pobj) {
00867 xp->parent = 0;
00868 sqlite3_result_null(ctx);
00869 goto done;
00870 }
00871 if ((xp->pobj->type == XPATH_NODESET) && xp->pobj->nodesetval) {
00872 if ((xp->pos < 0) || (xp->pos >= xp->pobj->nodesetval->nodeNr)) {
00873 xp->parent = 0;
00874 sqlite3_result_null(ctx);
00875 } else {
00876 xmlNodePtr node = xp->pobj->nodesetval->nodeTab[xp->pos];
00877 xmlBufferPtr buf = 0;
00878
00879 xp->parent = node->parent;
00880 if (node) {
00881 switch (xp->conv) {
00882 case 1:
00883 p = (char *) xmlXPathCastNodeToString(node);
00884 n = xmlXPathCastStringToBoolean((xmlChar *) p);
00885 sqlite3_result_int(ctx, n);
00886 if (p) {
00887 xmlFree(p);
00888 }
00889 break;
00890 case 2:
00891 sqlite3_result_double(ctx,
00892 xmlXPathCastNodeToNumber(node));
00893 break;
00894 case 3:
00895 buf = xmlBufferCreate();
00896 if (!buf) {
00897 sqlite3_result_error(ctx, "out of memory", -1);
00898 goto done;
00899 }
00900 xmlNodeDump(buf, xp->doc, node, 0, 0);
00901 sqlite3_result_text(ctx, (char *) xmlBufferContent(buf),
00902 xmlBufferLength(buf),
00903 SQLITE_TRANSIENT);
00904 xmlBufferFree(buf);
00905 break;
00906 default:
00907 p = (char *) xmlXPathCastNodeToString(node);
00908 sqlite3_result_text(ctx, p, -1, SQLITE_TRANSIENT);
00909 if (p) {
00910 xmlFree(p);
00911 }
00912 break;
00913 }
00914 } else {
00915 sqlite3_result_null(ctx);
00916 }
00917 }
00918 } else {
00919 xp->parent = 0;
00920 switch (xp->conv) {
00921 case 1:
00922 sqlite3_result_int(ctx, xmlXPathCastToBoolean(xp->pobj));
00923 break;
00924 case 2:
00925 sqlite3_result_double(ctx, xmlXPathCastToNumber(xp->pobj));
00926 break;
00927 default:
00928 p = (char *) xmlXPathCastToString(xp->pobj);
00929 sqlite3_result_text(ctx, p, -1, SQLITE_TRANSIENT);
00930 if (p) {
00931 xmlFree(p);
00932 }
00933 break;
00934 }
00935 }
00936 done:
00937 if (pobj) {
00938 xmlXPathFreeObject(pobj);
00939 }
00940 if (pctx) {
00941 xmlXPathFreeContext(pctx);
00942 }
00943 }
00944
00952 static void
00953 xpath_vfunc_string(sqlite3_context *ctx, int argc, sqlite3_value **argv)
00954 {
00955 return xpath_vfunc_common(ctx, 0, argc, argv);
00956 }
00957
00965 static void
00966 xpath_vfunc_boolean(sqlite3_context *ctx, int argc, sqlite3_value **argv)
00967 {
00968 return xpath_vfunc_common(ctx, 1, argc, argv);
00969 }
00970
00978 static void
00979 xpath_vfunc_number(sqlite3_context *ctx, int argc, sqlite3_value **argv)
00980 {
00981 return xpath_vfunc_common(ctx, 2, argc, argv);
00982 }
00983
00991 static void
00992 xpath_vfunc_xml(sqlite3_context *ctx, int argc, sqlite3_value **argv)
00993 {
00994 return xpath_vfunc_common(ctx, 3, argc, argv);
00995 }
00996
01007 static int
01008 xpath_findfunc(sqlite3_vtab *vtab, int nargs, const char *name,
01009 void (**pfunc)(sqlite3_context *, int, sqlite3_value **),
01010 void **parg)
01011 {
01012 if (nargs != 2) {
01013 return 0;
01014 }
01015 if (!strcmp(name, "xpath_string")) {
01016 *pfunc = xpath_vfunc_string;
01017 *parg = vtab;
01018 return 1;
01019 }
01020 if (!strcmp(name, "xpath_boolean")) {
01021 *pfunc = xpath_vfunc_boolean;
01022 *parg = vtab;
01023 return 1;
01024 }
01025 if (!strcmp(name, "xpath_number")) {
01026 *pfunc = xpath_vfunc_number;
01027 *parg = vtab;
01028 return 1;
01029 }
01030 if (!strcmp(name, "xpath_xml")) {
01031 *pfunc = xpath_vfunc_xml;
01032 *parg = vtab;
01033 return 1;
01034 }
01035 return 0;
01036 }
01037
01038 #if (SQLITE_VERSION_NUMBER > 3004000)
01039
01046 static int
01047 xpath_rename(sqlite3_vtab *vtab, const char *newname)
01048 {
01049 return SQLITE_OK;
01050 }
01051
01052 #endif
01053
01058 static sqlite3_module xpath_mod = {
01059 1,
01060 xpath_create,
01061 xpath_connect,
01062 xpath_bestindex,
01063 xpath_disconnect,
01064 xpath_destroy,
01065 xpath_open,
01066 xpath_close,
01067 xpath_filter,
01068 xpath_next,
01069 xpath_eof,
01070 xpath_column,
01071 xpath_rowid,
01072 xpath_update,
01073 0,
01074 0,
01075 0,
01076 0,
01077 xpath_findfunc,
01078 #if (SQLITE_VERSION_NUMBER > 3004000)
01079 xpath_rename,
01080 #endif
01081 };
01082
01105 static void
01106 xpath_func_common(sqlite3_context *ctx, int conv,
01107 int argc, sqlite3_value **argv)
01108 {
01109 xmlDocPtr doc = 0, docToFree = 0;
01110 xmlXPathContextPtr pctx = 0;
01111 xmlXPathObjectPtr pobj = 0;
01112 XMOD *xm = (XMOD *) sqlite3_user_data(ctx);
01113 int index = 0;
01114 char *p;
01115
01116 if (argc < 2) {
01117 sqlite3_result_null(ctx);
01118 goto done;
01119 }
01120 if (sqlite3_value_type(argv[0]) == SQLITE_INTEGER) {
01121 index = sqlite3_value_int(argv[0]);
01122 if (!xm->mutex) {
01123 sqlite3_result_error(ctx, "init error", -1);
01124 goto done;
01125 }
01126 sqlite3_mutex_enter(xm->mutex);
01127 if ((index <= 0) || (index > xm->sdoc) || !xm->docs[index - 1].doc) {
01128 sqlite3_mutex_leave(xm->mutex);
01129 sqlite3_result_error(ctx, "invalid DOCID", -1);
01130 goto done;
01131 }
01132 doc = xm->docs[index - 1].doc;
01133 xm->docs[index - 1].refcnt += 1;
01134 sqlite3_mutex_leave(xm->mutex);
01135 } else {
01136 int opts = (XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
01137 char *enc = 0, *url = 0;
01138
01139 p = (char *) sqlite3_value_blob(argv[0]);
01140 if (!p) {
01141 sqlite3_result_null(ctx);
01142 return;
01143 }
01144 if ((argc > 2) && (sqlite3_value_type(argv[2]) != SQLITE_NULL)) {
01145 opts = sqlite3_value_int(argv[2]);
01146 }
01147 if ((argc > 3) && (sqlite3_value_type(argv[3]) != SQLITE_NULL)) {
01148 enc = (char *) sqlite3_value_text(argv[3]);
01149 }
01150 if ((argc > 4) && (sqlite3_value_type(argv[4]) != SQLITE_NULL)) {
01151 url = (char *) sqlite3_value_text(argv[4]);
01152 }
01153 doc = xmlReadMemory(p, sqlite3_value_bytes(argv[0]),
01154 url ? url : "", enc, opts);
01155 docToFree = doc;
01156 if (!doc) {
01157 sqlite3_result_error(ctx, "read error", -1);
01158 goto done;
01159 }
01160 }
01161 p = (char *) sqlite3_value_text(argv[1]);
01162 if (!p) {
01163 sqlite3_result_null(ctx);
01164 goto done;
01165 }
01166 pctx = xmlXPathNewContext(doc);
01167 if (!pctx) {
01168 sqlite3_result_error(ctx, "out of memory", -1);
01169 goto done;
01170 }
01171 pobj = xmlXPathEvalExpression((xmlChar *) p, pctx);
01172 if (!pobj) {
01173 sqlite3_result_error(ctx, "bad XPath expression", -1);
01174 goto done;
01175 }
01176 switch (conv) {
01177 case 1:
01178 sqlite3_result_int(ctx, xmlXPathCastToBoolean(pobj));
01179 break;
01180 case 2:
01181 sqlite3_result_double(ctx, xmlXPathCastToNumber(pobj));
01182 break;
01183 case 3:
01184 if ((pobj->type == XPATH_NODESET) && pobj->nodesetval &&
01185 (pobj->nodesetval->nodeNr)) {
01186 xmlNodePtr node = pobj->nodesetval->nodeTab[0];
01187 xmlBufferPtr buf = 0;
01188
01189 buf = xmlBufferCreate();
01190 if (!buf) {
01191 sqlite3_result_error(ctx, "out of memory", -1);
01192 goto done;
01193 }
01194 xmlNodeDump(buf, doc, node, 0, 0);
01195 sqlite3_result_text(ctx, (char *) xmlBufferContent(buf),
01196 xmlBufferLength(buf), SQLITE_TRANSIENT);
01197 xmlBufferFree(buf);
01198 } else {
01199 sqlite3_result_null(ctx);
01200 }
01201 break;
01202 default:
01203 p = (char *) xmlXPathCastToString(pobj);
01204 sqlite3_result_text(ctx, p, -1, SQLITE_TRANSIENT);
01205 if (p) {
01206 xmlFree(p);
01207 }
01208 break;
01209 }
01210 done:
01211 if (pobj) {
01212 xmlXPathFreeObject(pobj);
01213 }
01214 if (pctx) {
01215 xmlXPathFreeContext(pctx);
01216 }
01217 if (docToFree) {
01218 xmlFreeDoc(docToFree);
01219 } else if (doc) {
01220 if (xm->mutex) {
01221 sqlite3_mutex_enter(xm->mutex);
01222 if (xm->docs && index) {
01223 xm->docs[index - 1].refcnt -= 1;
01224 if (xm->docs[index - 1].refcnt <= 0) {
01225 docToFree = doc;
01226 xm->docs[index - 1].refcnt = 0;
01227 xm->docs[index - 1].doc = 0;
01228 }
01229 }
01230 sqlite3_mutex_leave(xm->mutex);
01231 if (docToFree) {
01232 xmlFreeDoc(docToFree);
01233 }
01234 }
01235 }
01236 }
01237
01245 static void
01246 xpath_func_string(sqlite3_context *ctx, int argc, sqlite3_value **argv)
01247 {
01248 xpath_func_common(ctx, 0, argc, argv);
01249 }
01250
01258 static void
01259 xpath_func_boolean(sqlite3_context *ctx, int argc, sqlite3_value **argv)
01260 {
01261 xpath_func_common(ctx, 1, argc, argv);
01262 }
01263
01271 static void
01272 xpath_func_number(sqlite3_context *ctx, int argc, sqlite3_value **argv)
01273 {
01274 xpath_func_common(ctx, 2, argc, argv);
01275 }
01276
01284 static void
01285 xpath_func_xml(sqlite3_context *ctx, int argc, sqlite3_value **argv)
01286 {
01287 xpath_func_common(ctx, 3, argc, argv);
01288 }
01289
01307 static void
01308 xpath_func_dump(sqlite3_context *ctx, int argc, sqlite3_value **argv)
01309 {
01310 XMOD *xm = (XMOD *) sqlite3_user_data(ctx);
01311 int index = 0, dump_len = 0, fmt = 1;
01312 xmlChar *dump = 0;
01313 char *enc = "utf-8";
01314
01315 if (argc < 1) {
01316 sqlite3_result_null(ctx);
01317 return;
01318 }
01319 index = sqlite3_value_int(argv[0]);
01320 if (argc > 1) {
01321 enc = (char *) sqlite3_value_text(argv[1]);
01322 if (!enc) {
01323 enc = "utf-8";
01324 }
01325 }
01326 if (argc > 2) {
01327 fmt = sqlite3_value_int(argv[2]);
01328 }
01329 if (!xm->mutex) {
01330 sqlite3_result_error(ctx, "init error", -1);
01331 return;
01332 }
01333 sqlite3_mutex_enter(xm->mutex);
01334 if ((index <= 0) || (index > xm->sdoc) || !xm->docs[index - 1].doc) {
01335 sqlite3_mutex_leave(xm->mutex);
01336 sqlite3_result_error(ctx, "invalid DOCID", -1);
01337 return;
01338 }
01339 xmlDocDumpFormatMemoryEnc(xm->docs[index - 1].doc, &dump, &dump_len,
01340 enc, fmt);
01341 if (dump) {
01342 sqlite3_result_text(ctx, (char *) dump, dump_len, SQLITE_TRANSIENT);
01343 xmlFree(dump);
01344 }
01345 sqlite3_mutex_leave(xm->mutex);
01346 }
01347
01348 #ifdef WITH_XSLT
01349
01372 static void
01373 xpath_func_transform(sqlite3_context *ctx, int argc, sqlite3_value **argv)
01374 {
01375 xmlDocPtr doc = 0, docToFree = 0, res = 0;
01376 xsltStylesheetPtr cur = 0;
01377 XMOD *xm = (XMOD *) sqlite3_user_data(ctx);
01378 int index = 0, nparams = 0, param0, i;
01379 char *p;
01380 const char **params = 0;
01381
01382 if (argc < 2) {
01383 sqlite3_result_null(ctx);
01384 goto done;
01385 }
01386 if (sqlite3_value_type(argv[0]) == SQLITE_INTEGER) {
01387 index = sqlite3_value_int(argv[0]);
01388 if (!xm->mutex) {
01389 sqlite3_result_error(ctx, "init error", -1);
01390 goto done;
01391 }
01392 sqlite3_mutex_enter(xm->mutex);
01393 if ((index <= 0) || (index > xm->sdoc) || !xm->docs[index - 1].doc) {
01394 sqlite3_mutex_leave(xm->mutex);
01395 sqlite3_result_error(ctx, "invalid DOCID", -1);
01396 goto done;
01397 }
01398 doc = xm->docs[index - 1].doc;
01399 xm->docs[index - 1].refcnt += 1;
01400 sqlite3_mutex_leave(xm->mutex);
01401 param0 = 2;
01402 nparams = argc - 2;
01403 } else {
01404 int opts = (XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
01405 char *enc = 0, *url = 0;
01406
01407 p = (char *) sqlite3_value_blob(argv[0]);
01408 if (!p) {
01409 sqlite3_result_null(ctx);
01410 return;
01411 }
01412 if ((argc > 2) && (sqlite3_value_type(argv[2]) != SQLITE_NULL)) {
01413 opts = sqlite3_value_int(argv[2]);
01414 }
01415 if ((argc > 3) && (sqlite3_value_type(argv[3]) != SQLITE_NULL)) {
01416 enc = (char *) sqlite3_value_text(argv[3]);
01417 }
01418 if ((argc > 4) && (sqlite3_value_type(argv[4]) != SQLITE_NULL)) {
01419 url = (char *) sqlite3_value_text(argv[4]);
01420 }
01421 doc = xmlReadMemory(p, sqlite3_value_bytes(argv[0]),
01422 url ? url : "", enc, opts);
01423 docToFree = doc;
01424 if (!doc) {
01425 sqlite3_result_error(ctx, "read error", -1);
01426 goto done;
01427 }
01428 param0 = 5;
01429 nparams = argc - 5;
01430 }
01431 p = (char *) sqlite3_value_text(argv[1]);
01432 if (!p) {
01433 sqlite3_result_null(ctx);
01434 goto done;
01435 }
01436 cur = xsltParseStylesheetFile((xmlChar *) p);
01437 if (!cur) {
01438 sqlite3_result_error(ctx, "read error on stylesheet", -1);
01439 goto done;
01440 }
01441 if (nparams <= 0) {
01442 nparams = 1;
01443 } else {
01444 nparams++;
01445 }
01446 params = sqlite3_malloc(nparams * sizeof (char *));
01447 if (!params) {
01448 sqlite3_result_error(ctx, "out of memory", -1);
01449 goto done;
01450 }
01451 for (i = 0; i < (argc - param0); i++) {
01452 params[i] = (const char *) sqlite3_value_text(argv[i + param0]);
01453 if (!params[i]) {
01454 params[i] = "";
01455 }
01456 }
01457 params[i] = 0;
01458 res = xsltApplyStylesheet(cur, doc, params);
01459 if (!res) {
01460 sqlite3_result_error(ctx, "transformation failed", -1);
01461 goto done;
01462 }
01463 if (docToFree) {
01464 xmlChar *str = 0;
01465
01466 xmlFreeDoc(docToFree);
01467 docToFree = res;
01468 i = 0;
01469 xsltSaveResultToString(&str, &i, res, cur);
01470 if (str) {
01471 sqlite3_result_text(ctx, (char *) str, i, SQLITE_TRANSIENT);
01472 xmlFree(str);
01473 } else {
01474 sqlite3_result_null(ctx);
01475 }
01476 }
01477 done:
01478 if (params) {
01479 sqlite3_free(params);
01480 }
01481 if (cur) {
01482 xsltFreeStylesheet(cur);
01483 }
01484 if (docToFree) {
01485 xmlFreeDoc(docToFree);
01486 } else if (doc) {
01487 if (xm->mutex) {
01488 sqlite3_mutex_enter(xm->mutex);
01489 if (xm->docs && index) {
01490 docToFree = doc;
01491 xm->docs[index - 1].doc = 0;
01492 xmlFreeDoc(docToFree);
01493 docToFree = 0;
01494 xm->docs[index - 1].refcnt -= 1;
01495 xm->docs[index - 1].doc = res;
01496 if (xm->docs[index - 1].refcnt <= 0) {
01497 docToFree = res;
01498 xm->docs[index - 1].refcnt = 0;
01499 xm->docs[index - 1].doc = 0;
01500 }
01501 }
01502 sqlite3_mutex_leave(xm->mutex);
01503 if (docToFree) {
01504 xmlFreeDoc(docToFree);
01505 }
01506 }
01507 }
01508 }
01509 #endif
01510
01517 static void
01518 xpath_fini(void *aux)
01519 {
01520 XMOD *xm = (XMOD *) aux;
01521 XDOC *docs;
01522 int i, n, cleanup = 0;
01523 sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
01524
01525 if (!mutex) {
01526 return;
01527 }
01528 sqlite3_mutex_enter(mutex);
01529 if (initialized) {
01530 xm->refcnt--;
01531 if (xm->refcnt <= 0) {
01532 xmod = 0;
01533 initialized = 0;
01534 cleanup = 1;
01535 }
01536 } else {
01537 cleanup = 1;
01538 }
01539 sqlite3_mutex_leave(mutex);
01540 if (cleanup) {
01541 sqlite3_mutex_enter(xm->mutex);
01542 mutex = xm->mutex;
01543 xm->mutex = 0;
01544 docs = xm->docs;
01545 n = xm->ndoc;
01546 xm->docs = 0;
01547 xm->sdoc = xm->ndoc = 0;
01548 sqlite3_mutex_leave(mutex);
01549 sqlite3_mutex_free(mutex);
01550 for (i = 0; i < n; i++) {
01551 if (docs->refcnt <= 0) {
01552 xmlFreeDoc(docs->doc);
01553 docs->doc = 0;
01554 }
01555 }
01556 sqlite3_free(docs);
01557 sqlite3_free(xm);
01558 }
01559 }
01560
01567 #ifndef STANDALONE
01568 static
01569 #endif
01570 int
01571 xpath_init(sqlite3 *db)
01572 {
01573 XMOD *xm;
01574 int rc;
01575 sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
01576
01577 if (!mutex) {
01578 return SQLITE_NOMEM;
01579 }
01580 sqlite3_mutex_enter(mutex);
01581 if (!initialized) {
01582 xm = sqlite3_malloc(sizeof (XMOD));
01583 if (!xm) {
01584 sqlite3_mutex_leave(mutex);
01585 return SQLITE_NOMEM;
01586 }
01587 xm->refcnt = 1;
01588 xm->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
01589 if (!xm->mutex) {
01590 sqlite3_mutex_leave(mutex);
01591 sqlite3_free(xm);
01592 return SQLITE_NOMEM;
01593 }
01594 xm->sdoc = 128;
01595 xm->ndoc = 0;
01596 xm->docs = sqlite3_malloc(xm->sdoc * sizeof (XDOC));
01597 if (!xm->docs) {
01598 sqlite3_mutex_leave(mutex);
01599 sqlite3_mutex_free(xm->mutex);
01600 sqlite3_free(xm);
01601 return SQLITE_NOMEM;
01602 }
01603 memset(xm->docs, 0, xm->sdoc * sizeof (XDOC));
01604 xmod = xm;
01605 initialized = 1;
01606 } else {
01607 xm = xmod;
01608 xm->refcnt++;
01609 }
01610 sqlite3_mutex_leave(mutex);
01611 sqlite3_create_function(db, "xpath_string", -1, SQLITE_UTF8,
01612 (void *) xm, xpath_func_string, 0, 0);
01613 sqlite3_create_function(db, "xpath_boolean", -1, SQLITE_UTF8,
01614 (void *) xm, xpath_func_boolean, 0, 0);
01615 sqlite3_create_function(db, "xpath_number", -1, SQLITE_UTF8,
01616 (void *) xm, xpath_func_number, 0, 0);
01617 sqlite3_create_function(db, "xpath_xml", -1, SQLITE_UTF8,
01618 (void *) xm, xpath_func_xml, 0, 0);
01619 sqlite3_create_function(db, "xml_dump", -1, SQLITE_UTF8,
01620 (void *) xm, xpath_func_dump, 0, 0);
01621 #ifdef WITH_XSLT
01622 sqlite3_create_function(db, "xslt_transform", -1, SQLITE_UTF8,
01623 (void *) xm, xpath_func_transform, 0, 0);
01624 #endif
01625 rc = sqlite3_create_module_v2(db, "xpath", &xpath_mod,
01626 (void *) xm, xpath_fini);
01627 if (rc != SQLITE_OK) {
01628 sqlite3_create_function(db, "xpath_string", -1, SQLITE_UTF8,
01629 (void *) xm, 0, 0, 0);
01630 sqlite3_create_function(db, "xpath_boolean", -1, SQLITE_UTF8,
01631 (void *) xm, 0, 0, 0);
01632 sqlite3_create_function(db, "xpath_number", -1, SQLITE_UTF8,
01633 (void *) xm, 0, 0, 0);
01634 sqlite3_create_function(db, "xpath_xml", -1, SQLITE_UTF8,
01635 (void *) xm, 0, 0, 0);
01636 sqlite3_create_function(db, "xml_dump", -1, SQLITE_UTF8,
01637 (void *) xm, 0, 0, 0);
01638 #ifdef WITH_XSLT
01639 sqlite3_create_function(db, "xslt_transform", -1, SQLITE_UTF8,
01640 (void *) xm, 0, 0, 0);
01641 #endif
01642 xpath_fini(xm);
01643 }
01644 return rc;
01645 }
01646
01647 #ifndef STANDALONE
01648
01657 int
01658 sqlite3_extension_init(sqlite3 *db, char **errmsg,
01659 const sqlite3_api_routines *api)
01660 {
01661 SQLITE_EXTENSION_INIT2(api);
01662 return xpath_init(db);
01663 }
01664
01665 #endif