Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

xpath.c

Go to the documentation of this file.
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         /* DELETE */
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         /* INSERT */
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         /* UPDATE */
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,                  /* iVersion */
01060     xpath_create,       /* xCreate */
01061     xpath_connect,      /* xConnect */
01062     xpath_bestindex,    /* xBestIndex */
01063     xpath_disconnect,   /* xDisconnect */
01064     xpath_destroy,      /* xDestroy */
01065     xpath_open,         /* xOpen */
01066     xpath_close,        /* xClose */
01067     xpath_filter,       /* xFilter */
01068     xpath_next,         /* xNext */
01069     xpath_eof,          /* xEof */
01070     xpath_column,       /* xColumn */
01071     xpath_rowid,        /* xRowid */
01072     xpath_update,       /* xUpdate */
01073     0,                  /* xBegin */
01074     0,                  /* xSync */
01075     0,                  /* xCommit */
01076     0,                  /* xRollback */
01077     xpath_findfunc,     /* xFindFunction */
01078 #if (SQLITE_VERSION_NUMBER > 3004000)
01079     xpath_rename,       /* xRename */
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

Generated on 23 Oct 2023 by doxygen.
Contact: chw@ch-werner.de