1 /*
2
3 virtualxpath.c -- SQLite3 extension [VIRTUAL XPath handler]
4
5 version 5.0, 2020 August 1
6
7 Author: Sandro Furieri a.furieri@lqt.it
8
9 -----------------------------------------------------------------------------
10
11 Version: MPL 1.1/GPL 2.0/LGPL 2.1
12
13 The contents of this file are subject to the Mozilla Public License Version
14 1.1 (the "License"); you may not use this file except in compliance with
15 the License. You may obtain a copy of the License at
16 http://www.mozilla.org/MPL/
17
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22
23 The Original Code is the SpatiaLite library
24
25 The Initial Developer of the Original Code is Alessandro Furieri
26
27 Portions created by the Initial Developer are Copyright (C) 2008-2021
28 the Initial Developer. All Rights Reserved.
29
30 Contributor(s):
31
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43
44 */
45
46 #include <sys/types.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <math.h>
51
52 #if defined(_WIN32) && !defined(__MINGW32__)
53 #include "config-msvc.h"
54 #else
55 #include "config.h"
56 #endif
57
58 #ifdef ENABLE_LIBXML2 /* LIBXML2 enabled: supporting XML documents */
59
60 #include <libxml/parser.h>
61 #include <libxml/xpath.h>
62 #include <libxml/xpathInternals.h>
63
64 #if defined(_WIN32) && !defined(__MINGW32__)
65 #define LONG64_MAX _I64_MAX
66 #define LONG64_MIN _I64_MIN
67 #else
68 #define LONG64_MAX 9223372036854775807LL
69 #define LONG64_MIN (-LONG64_MAX + 1)
70 #endif
71
72 #include <spatialite/sqlite.h>
73
74 #include <spatialite/spatialite_ext.h>
75 #include <spatialite/debug.h>
76 #include <spatialite/gaiaaux.h>
77 #include <spatialite/gaiageo.h>
78
79 #ifdef _WIN32
80 #define strcasecmp _stricmp
81 #define strncasecmp _strnicmp
82 #endif /* not WIN32 */
83
84 static struct sqlite3_module my_xpath_module;
85
86 /******************************************************************************
87 /
88 / VirtualTable structs
89 /
90 ******************************************************************************/
91
92 typedef struct VirtualXPathStruct
93 {
94 /* extends the sqlite3_vtab struct */
95 const sqlite3_module *pModule; /* ptr to sqlite module: USED INTERNALLY BY SQLITE */
96 int nRef; /* # references: USED INTERNALLY BY SQLITE */
97 char *zErrMsg; /* error message: USE INTERNALLY BY SQLITE */
98 sqlite3 *db; /* the sqlite db holding the virtual table */
99 const void *p_cache; /* pointer to the internal cache */
100 char *table; /* the real-table name */
101 char *column; /* the real-column name */
102 } VirtualXPath;
103 typedef VirtualXPath *VirtualXPathPtr;
104
105 typedef struct VirtualXPathCursorStruct
106 {
107 /* extends the sqlite3_vtab_cursor struct */
108 VirtualXPathPtr pVtab; /* Virtual table of this cursor */
109 int eof; /* the EOF marker */
110 sqlite3_stmt *stmt;
111 char *xpathExpr;
112 xmlDocPtr xmlDoc;
113 xmlXPathContextPtr xpathContext;
114 xmlXPathObjectPtr xpathObj;
115 int xpathIdx;
116 sqlite3_int64 current_row;
117 int keyOp1;
118 sqlite3_int64 keyVal1;
119 int keyOp2;
120 sqlite3_int64 keyVal2;
121 } VirtualXPathCursor;
122 typedef VirtualXPathCursor *VirtualXPathCursorPtr;
123
124 static void
vxpath_free_ns(struct vxpath_ns * ns)125 vxpath_free_ns (struct vxpath_ns *ns)
126 {
127 /* memory cleanup - destroying a Namespace item */
128 if (!ns)
129 return;
130 if (ns->Prefix)
131 free (ns->Prefix);
132 if (ns->Href)
133 free (ns->Href);
134 free (ns);
135 }
136
137 SPATIALITE_PRIVATE void
vxpath_free_namespaces(struct vxpath_namespaces * ns_list)138 vxpath_free_namespaces (struct vxpath_namespaces *ns_list)
139 {
140 /* memory cleanup - destroying the Namespaces list */
141 struct vxpath_ns *ns;
142 struct vxpath_ns *nns;
143 if (!ns_list)
144 return;
145
146 ns = ns_list->First;
147 while (ns)
148 {
149 nns = ns->Next;
150 vxpath_free_ns (ns);
151 ns = nns;
152 }
153 free (ns_list);
154 }
155
156 static void
vxpath_add_ns(struct vxpath_namespaces * ns_list,const char * prefix,const char * href)157 vxpath_add_ns (struct vxpath_namespaces *ns_list, const char *prefix,
158 const char *href)
159 {
160 /* inserting a further Namespace into the list */
161 int len;
162 struct vxpath_ns *ns = ns_list->First;
163 while (ns)
164 {
165 /* checking if it's already defined */
166 if (ns->Prefix == NULL || prefix == NULL)
167 {
168 if (ns->Prefix == NULL && prefix == NULL
169 && strcmp (ns->Href, href) == 0)
170 {
171 /* ok, already defined (default Namespace) */
172 return;
173 }
174 }
175 else
176 {
177 if (strcmp (ns->Prefix, prefix) == 0
178 && strcmp (ns->Href, href) == 0)
179 {
180 /* ok, already defined */
181 return;
182 }
183 }
184 ns = ns->Next;
185 }
186
187 /* inserting a new Namespace */
188 ns = malloc (sizeof (struct vxpath_ns));
189 if (prefix == NULL)
190 ns->Prefix = NULL;
191 else
192 {
193 len = strlen (prefix);
194 ns->Prefix = malloc (len + 1);
195 strcpy (ns->Prefix, prefix);
196 }
197 len = strlen (href);
198 ns->Href = malloc (len + 1);
199 strcpy (ns->Href, href);
200 ns->Next = NULL;
201 if (ns_list->First == NULL)
202 ns_list->First = ns;
203 if (ns_list->Last != NULL)
204 ns_list->Last->Next = ns;
205 ns_list->Last = ns;
206 }
207
208 static void
vxpath_feed_ns(struct vxpath_namespaces * ns_list,xmlNodePtr start)209 vxpath_feed_ns (struct vxpath_namespaces *ns_list, xmlNodePtr start)
210 {
211 /* recursively searching for Namespaces */
212 xmlNodePtr node = start;
213 while (node)
214 {
215 if (node->ns != NULL)
216 {
217 /* a Namespace is defined */
218 vxpath_add_ns (ns_list, (const char *) (node->ns->prefix),
219 (const char *) (node->ns->href));
220 }
221 if (node->properties != NULL)
222 {
223 /* exploring the Attribute list */
224 struct _xmlAttr *attr = node->properties;
225 while (attr)
226 {
227 if (attr->type == XML_ATTRIBUTE_NODE)
228 {
229 if (attr->ns != NULL)
230 {
231 /* a Namespace is defined */
232 vxpath_add_ns (ns_list,
233 (const char *) (attr->ns->
234 prefix),
235 (const char *) (attr->ns->
236 href));
237 }
238 }
239 attr = attr->next;
240 }
241 }
242 vxpath_feed_ns (ns_list, node->children);
243 node = node->next;
244 }
245 }
246
247 SPATIALITE_PRIVATE struct vxpath_namespaces *
vxpath_get_namespaces(void * p_xml_doc)248 vxpath_get_namespaces (void *p_xml_doc)
249 {
250 /* creating and populating the Namespaces list */
251 xmlDocPtr xml_doc = (xmlDocPtr) p_xml_doc;
252 xmlNodePtr root = xmlDocGetRootElement (xml_doc);
253 struct vxpath_namespaces *ns_list;
254 ns_list = malloc (sizeof (struct vxpath_namespaces));
255 ns_list->First = NULL;
256 ns_list->Last = NULL;
257 vxpath_feed_ns (ns_list, root);
258 return ns_list;
259 }
260
261 static int
is_valid_cache(struct splite_internal_cache * cache)262 is_valid_cache (struct splite_internal_cache *cache)
263 {
264 /* testing if the passed cache is a valid one */
265 if (cache == NULL)
266 return 0;
267 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
268 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
269 return 0;
270 return 1;
271 }
272
273 static void
vxpathError(void * ctx,const char * msg,...)274 vxpathError (void *ctx, const char *msg, ...)
275 {
276 /* appending to the current XPath Error buffer */
277 struct splite_internal_cache *cache = (struct splite_internal_cache *) ctx;
278 gaiaOutBufferPtr buf;
279 char out[65536];
280 va_list args;
281
282 if (ctx != NULL)
283 ctx = NULL; /* suppressing stupid compiler warnings (unused args) */
284 if (!is_valid_cache (cache))
285 return;
286 buf = (gaiaOutBufferPtr) (cache->xmlXPathErrors);
287
288 va_start (args, msg);
289 vsnprintf (out, 65536, msg, args);
290 gaiaAppendToOutBuffer (buf, out);
291 va_end (args);
292 }
293
294 static void
vxpathResetXmlErrors(struct splite_internal_cache * cache)295 vxpathResetXmlErrors (struct splite_internal_cache *cache)
296 {
297 /* resetting the XPath Error buffer */
298 gaiaOutBufferPtr buf;
299 if (!is_valid_cache (cache))
300 return;
301 buf = (gaiaOutBufferPtr) (cache->xmlXPathErrors);
302 gaiaOutBufferReset (buf);
303 }
304
305 GAIAGEO_DECLARE int
gaiaIsValidXPathExpression(const void * p_cache,const char * xpath_expr)306 gaiaIsValidXPathExpression (const void *p_cache, const char *xpath_expr)
307 {
308 struct splite_internal_cache *cache =
309 (struct splite_internal_cache *) p_cache;
310 xmlXPathCompExprPtr result;
311 xmlGenericErrorFunc xpathError;
312 if (!is_valid_cache (cache))
313 return 0;
314 xpathError = (xmlGenericErrorFunc) vxpathError;
315
316 vxpathResetXmlErrors (cache);
317 xmlSetGenericErrorFunc (cache, xpathError);
318
319 /* testing an XPath expression */
320 result = xmlXPathCompile ((const xmlChar *) xpath_expr);
321 xmlSetGenericErrorFunc ((void *) stderr, NULL);
322 if (result)
323 {
324 xmlXPathFreeCompExpr (result);
325 return 1;
326 }
327 return 0;
328 }
329
330 SPATIALITE_PRIVATE int
vxpath_eval_expr(const void * p_cache,void * x_xml_doc,const char * xpath_expr,void * x_xpathCtx,void * x_xpathObj)331 vxpath_eval_expr (const void *p_cache, void *x_xml_doc, const char *xpath_expr,
332 void *x_xpathCtx, void *x_xpathObj)
333 {
334 struct splite_internal_cache *cache =
335 (struct splite_internal_cache *) p_cache;
336 /* evaluating an XPath expression */
337 xmlDocPtr xml_doc = (xmlDocPtr) x_xml_doc;
338 xmlXPathContextPtr *p_xpathCtx = (xmlXPathContextPtr *) x_xpathCtx;
339 xmlXPathObjectPtr *p_xpathObj = (xmlXPathObjectPtr *) x_xpathObj;
340 xmlXPathObjectPtr xpathObj;
341 xmlXPathContextPtr xpathCtx;
342 xmlGenericErrorFunc xpathError = (xmlGenericErrorFunc) vxpathError;
343
344 /* attempting to identify all required Namespaces */
345 struct vxpath_ns *ns;
346 struct vxpath_namespaces *ns_list = vxpath_get_namespaces (xml_doc);
347
348 if (is_valid_cache (cache))
349 {
350 vxpathResetXmlErrors (cache);
351 xmlSetGenericErrorFunc (cache, xpathError);
352 }
353
354 /* creating an XPath context */
355 xpathCtx = xmlXPathNewContext (xml_doc);
356 if (xpathCtx == NULL)
357 {
358 xmlSetGenericErrorFunc ((void *) stderr, NULL);
359 return 0;
360 }
361
362 /* registering all Namespaces */
363 if (xpathCtx != NULL && ns_list != NULL)
364 {
365 ns = ns_list->First;
366 while (ns)
367 {
368 if (ns->Prefix == NULL)
369 {
370 /* the default Namespace always is "dflt:xx" */
371 xmlXPathRegisterNs (xpathCtx, (xmlChar *) "dflt",
372 (xmlChar *) ns->Href);
373 }
374 else
375 {
376 /* a fully qualified Namespace */
377 xmlXPathRegisterNs (xpathCtx, (xmlChar *) ns->Prefix,
378 (xmlChar *) ns->Href);
379 }
380 ns = ns->Next;
381 }
382 }
383 vxpath_free_namespaces (ns_list);
384
385 /* evaluating the XPath expression */
386 xpathObj = xmlXPathEvalExpression ((const xmlChar *) xpath_expr, xpathCtx);
387 if (xpathObj != NULL)
388 {
389 xmlNodeSetPtr nodes = xpathObj->nodesetval;
390 int num_nodes = (nodes) ? nodes->nodeNr : 0;
391 if (num_nodes >= 1)
392 {
393 /* OK: match found */
394 *p_xpathCtx = xpathCtx;
395 *p_xpathObj = xpathObj;
396 xmlSetGenericErrorFunc ((void *) stderr, NULL);
397 return 1;
398 }
399 /* invalid: empty nodeset */
400 xmlXPathFreeObject (xpathObj);
401 }
402 xmlXPathFreeContext (xpathCtx);
403
404 xmlSetGenericErrorFunc ((void *) stderr, NULL);
405 return 0;
406 }
407
408 static void
vxpath_read_row(VirtualXPathCursorPtr cursor)409 vxpath_read_row (VirtualXPathCursorPtr cursor)
410 {
411 /* trying to read a row from the real-table */
412 sqlite3_stmt *stmt;
413 int ret;
414 sqlite3_int64 pk;
415 int eof;
416 if (cursor->stmt == NULL || cursor->xpathExpr == NULL)
417 return;
418
419 if (cursor->xpathObj)
420 xmlXPathFreeObject (cursor->xpathObj);
421 if (cursor->xpathContext)
422 xmlXPathFreeContext (cursor->xpathContext);
423 if (cursor->xmlDoc)
424 xmlFreeDoc (cursor->xmlDoc);
425 cursor->xmlDoc = NULL;
426 cursor->xpathContext = NULL;
427 cursor->xpathObj = NULL;
428
429 stmt = cursor->stmt;
430 sqlite3_bind_int64 (stmt, 1, cursor->current_row);
431 while (1)
432 {
433 ret = sqlite3_step (stmt);
434 if (ret == SQLITE_ROW)
435 {
436 pk = sqlite3_column_int64 (stmt, 0);
437 /* filtering the PK value */
438 eof = 0;
439 switch (cursor->keyOp1)
440 {
441 case SQLITE_INDEX_CONSTRAINT_EQ:
442 if (pk > cursor->keyVal1)
443 eof = 1;
444 break;
445 case SQLITE_INDEX_CONSTRAINT_LT:
446 if (pk >= cursor->keyVal1)
447 eof = 1;
448 break;
449 case SQLITE_INDEX_CONSTRAINT_LE:
450 if (pk > cursor->keyVal1)
451 eof = 1;
452 break;
453 };
454 switch (cursor->keyOp2)
455 {
456 case SQLITE_INDEX_CONSTRAINT_EQ:
457 if (pk > cursor->keyVal2)
458 eof = 1;
459 break;
460 case SQLITE_INDEX_CONSTRAINT_LT:
461 if (pk >= cursor->keyVal2)
462 eof = 1;
463 break;
464 case SQLITE_INDEX_CONSTRAINT_LE:
465 if (pk > cursor->keyVal2)
466 eof = 1;
467 break;
468 };
469 if (eof)
470 {
471 cursor->eof = 1;
472 return;
473 }
474
475 if (sqlite3_column_type (stmt, 1) == SQLITE_BLOB)
476 {
477 xmlDocPtr xml_doc;
478 int xml_len;
479 unsigned char *xml;
480 const unsigned char *blob = sqlite3_column_blob (stmt, 1);
481 int size = sqlite3_column_bytes (stmt, 1);
482 gaiaXmlFromBlob (blob, size, -1, &xml, &xml_len);
483 if (!xml)
484 continue;
485 xml_doc =
486 xmlReadMemory ((const char *) xml, xml_len,
487 "noname.xml", NULL, 0);
488 if (xml_doc != NULL)
489 {
490 xmlXPathContextPtr xpathCtx;
491 xmlXPathObjectPtr xpathObj;
492 if (vxpath_eval_expr
493 (cursor->pVtab->p_cache, xml_doc,
494 cursor->xpathExpr, &xpathCtx, &xpathObj))
495 {
496 free (xml);
497 if (cursor->xpathObj)
498 xmlXPathFreeObject (cursor->xpathObj);
499 if (cursor->xpathContext)
500 xmlXPathFreeContext
501 (cursor->xpathContext);
502 if (cursor->xmlDoc)
503 xmlFreeDoc (cursor->xmlDoc);
504 cursor->xmlDoc = xml_doc;
505 cursor->xpathContext = xpathCtx;
506 cursor->xpathObj = xpathObj;
507 cursor->xpathIdx = 0;
508 break;
509 }
510 free (xml);
511 xmlFreeDoc (xml_doc);
512 }
513 }
514 }
515 else
516 {
517 /* an error occurred */
518 cursor->eof = 1;
519 return;
520 }
521 }
522 cursor->eof = 0;
523 cursor->current_row = pk;
524 }
525
526 static void
vxpath_check(sqlite3 * db,const char * table,const char * column,int * okTable,int * okCol)527 vxpath_check (sqlite3 * db, const char *table, const char *column, int *okTable,
528 int *okCol)
529 {
530 /* checking if both Table and Column exist */
531 char **results;
532 char *sql;
533 char *xname;
534 int ret;
535 int i;
536 int n_rows;
537 int n_columns;
538 xname = gaiaDoubleQuotedSql (table);
539 sql = sqlite3_mprintf ("PRAGMA table_info(\"%s\")", xname);
540 free (xname);
541 ret = sqlite3_get_table (db, sql, &results, &n_rows, &n_columns, NULL);
542 sqlite3_free (sql);
543 if (ret != SQLITE_OK)
544 return;
545 if (n_rows >= 1)
546 {
547 *okTable = 1;
548 for (i = 1; i <= n_rows; i++)
549 {
550 const char *col_name = results[(i * n_columns) + 1];
551 if (strcasecmp (col_name, column) == 0)
552 *okCol = 1;
553 }
554 }
555 sqlite3_free_table (results);
556 }
557
558 static int
vxpath_create(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVTab,char ** pzErr)559 vxpath_create (sqlite3 * db, void *pAux, int argc, const char *const *argv,
560 sqlite3_vtab ** ppVTab, char **pzErr)
561 {
562 /* creates the virtual table for XPath */
563 VirtualXPathPtr p_vt;
564 char *vtable = NULL;
565 char *table = NULL;
566 char *column = NULL;
567 char *xname;
568 char *sql;
569 int okTable = 0;
570 int okCol = 0;
571 if (argc == 5)
572 {
573 vtable = gaiaDequotedSql ((char *) argv[2]);
574 table = gaiaDequotedSql ((char *) argv[3]);
575 column = gaiaDequotedSql ((char *) argv[4]);
576 }
577 else
578 {
579 *pzErr =
580 sqlite3_mprintf
581 ("[VirtualXPath module] CREATE VIRTUAL: illegal arg list {void}\n");
582 return SQLITE_ERROR;
583 }
584 vxpath_check (db, table, column, &okTable, &okCol);
585 if (!okTable || !okCol)
586 goto illegal;
587 xname = gaiaDoubleQuotedSql (vtable);
588 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (pkid INTEGER, sub INTEGER, "
589 "parent TEXT, node TEXT, attribute TEXT, "
590 "value TEXT, xpath_expr TEXT)", xname);
591 free (xname);
592 if (sqlite3_declare_vtab (db, sql) != SQLITE_OK)
593 {
594 sqlite3_free (sql);
595 *pzErr =
596 sqlite3_mprintf
597 ("[VirtualXPath module] CREATE VIRTUAL: invalid SQL statement \"%s\"",
598 sql);
599 goto error;
600 }
601 sqlite3_free (sql);
602 p_vt = (VirtualXPathPtr) sqlite3_malloc (sizeof (VirtualXPath));
603 if (!p_vt)
604 return SQLITE_NOMEM;
605 p_vt->db = db;
606 p_vt->p_cache = pAux;
607 if (p_vt->p_cache == NULL)
608 spatialite_e ("VirtualXPath WARNING - no XML cache is available !!!\n");
609 p_vt->nRef = 0;
610 p_vt->zErrMsg = NULL;
611 p_vt->table = table;
612 p_vt->column = column;
613 *ppVTab = (sqlite3_vtab *) p_vt;
614 free (vtable);
615 return SQLITE_OK;
616 illegal:
617 /* something is going the wrong way */
618 if (!okTable)
619 *pzErr =
620 sqlite3_mprintf
621 ("[VirtualXPath module] table \"%s\" doesn't exists\n", table);
622 else if (!okCol)
623 *pzErr =
624 sqlite3_mprintf
625 ("[VirtualXPath module] table \"%s\" exists, but has no \"%s\" column\n",
626 table, column);
627 error:
628 return SQLITE_ERROR;
629 }
630
631 static int
vxpath_connect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVTab,char ** pzErr)632 vxpath_connect (sqlite3 * db, void *pAux, int argc, const char *const *argv,
633 sqlite3_vtab ** ppVTab, char **pzErr)
634 {
635 /* connects the virtual table - simply aliases vxpath_create() */
636 return vxpath_create (db, pAux, argc, argv, ppVTab, pzErr);
637 }
638
639 static int
vxpath_best_index(sqlite3_vtab * pVTab,sqlite3_index_info * pIdxInfo)640 vxpath_best_index (sqlite3_vtab * pVTab, sqlite3_index_info * pIdxInfo)
641 {
642 /* best index selection */
643 int i;
644 int errors = 0;
645 int err = 1;
646 int xpath = 0;
647 if (pVTab)
648 pVTab = pVTab; /* unused arg warning suppression */
649 for (i = 0; i < pIdxInfo->nConstraint; i++)
650 {
651 /* verifying the constraints */
652 struct sqlite3_index_constraint *p = &(pIdxInfo->aConstraint[i]);
653 if (p->usable)
654 {
655 if (p->iColumn == 0);
656 else if (p->iColumn == 6 && p->op == SQLITE_INDEX_CONSTRAINT_EQ)
657 xpath++;
658 else
659 errors++;
660 }
661 }
662 if (xpath == 1 && errors == 0)
663 {
664 /* this one is a valid XPath query */
665 pIdxInfo->idxNum = 1;
666 pIdxInfo->estimatedCost = 1.0;
667 pIdxInfo->idxStr = sqlite3_malloc (pIdxInfo->nConstraint * 2);
668 pIdxInfo->needToFreeIdxStr = 1;
669 for (i = 0; i < pIdxInfo->nConstraint; i++)
670 {
671 struct sqlite3_index_constraint *p =
672 &(pIdxInfo->aConstraint[i]);
673 if (p->usable)
674 {
675 char *pStr = pIdxInfo->idxStr + (i * 2);
676 if (p->iColumn == 6)
677 *pStr = 0;
678 else
679 *pStr = 1;
680 pStr++;
681 *pStr = p->op;
682 pIdxInfo->aConstraintUsage[i].argvIndex = i + 1;
683 pIdxInfo->aConstraintUsage[i].omit = 1;
684 }
685 }
686 err = 0;
687 }
688 if (err)
689 {
690 /* illegal query */
691 pIdxInfo->idxNum = 0;
692 }
693 return SQLITE_OK;
694 }
695
696 static int
vxpath_disconnect(sqlite3_vtab * pVTab)697 vxpath_disconnect (sqlite3_vtab * pVTab)
698 {
699 /* disconnects the virtual table */
700 VirtualXPathPtr p_vt = (VirtualXPathPtr) pVTab;
701 free (p_vt->column);
702 free (p_vt->table);
703 sqlite3_free (p_vt);
704 return SQLITE_OK;
705 }
706
707 static int
vxpath_destroy(sqlite3_vtab * pVTab)708 vxpath_destroy (sqlite3_vtab * pVTab)
709 {
710 /* destroys the virtual table - simply aliases vxpath_disconnect() */
711 return vxpath_disconnect (pVTab);
712 }
713
714 static int
vxpath_open(sqlite3_vtab * pVTab,sqlite3_vtab_cursor ** ppCursor)715 vxpath_open (sqlite3_vtab * pVTab, sqlite3_vtab_cursor ** ppCursor)
716 {
717 /* opening a new cursor */
718 sqlite3_stmt *stmt;
719 int ret;
720 char *sql;
721 char *xname;
722 char *xcolumn;
723 VirtualXPathCursorPtr cursor =
724 (VirtualXPathCursorPtr) sqlite3_malloc (sizeof (VirtualXPathCursor));
725 if (cursor == NULL)
726 return SQLITE_ERROR;
727 cursor->pVtab = (VirtualXPathPtr) pVTab;
728 cursor->xmlDoc = NULL;
729 cursor->xpathContext = NULL;
730 cursor->xpathObj = NULL;
731 cursor->xpathExpr = NULL;
732 cursor->stmt = NULL;
733 cursor->keyOp1 = 0;
734 cursor->keyVal1 = 0;
735 cursor->keyOp2 = 0;
736 cursor->keyVal2 = 0;
737 xcolumn = gaiaDoubleQuotedSql (cursor->pVtab->column);
738 xname = gaiaDoubleQuotedSql (cursor->pVtab->table);
739 sql = sqlite3_mprintf ("SELECT ROWID, \"%s\" FROM \"%s\""
740 " WHERE ROWID >= ?", xcolumn, xname);
741 free (xname);
742 free (xcolumn);
743 ret =
744 sqlite3_prepare_v2 (cursor->pVtab->db, sql, strlen (sql), &stmt, NULL);
745 sqlite3_free (sql);
746 if (ret != SQLITE_OK)
747 {
748 /* an error occurred */
749 cursor->eof = 1;
750 return SQLITE_ERROR;
751 }
752 cursor->stmt = stmt;
753 cursor->current_row = LONG64_MIN;
754 cursor->eof = 0;
755 *ppCursor = (sqlite3_vtab_cursor *) cursor;
756 return SQLITE_OK;
757 }
758
759 static int
vxpath_close(sqlite3_vtab_cursor * pCursor)760 vxpath_close (sqlite3_vtab_cursor * pCursor)
761 {
762 /* closing the cursor */
763 VirtualXPathCursorPtr cursor = (VirtualXPathCursorPtr) pCursor;
764 if (cursor->stmt)
765 sqlite3_finalize (cursor->stmt);
766 if (cursor->xpathObj)
767 xmlXPathFreeObject (cursor->xpathObj);
768 if (cursor->xpathContext)
769 xmlXPathFreeContext (cursor->xpathContext);
770 if (cursor->xmlDoc)
771 xmlFreeDoc (cursor->xmlDoc);
772 if (cursor->xpathExpr)
773 free (cursor->xpathExpr);
774 sqlite3_free (pCursor);
775 return SQLITE_OK;
776 }
777
778 static int
vxpath_filter(sqlite3_vtab_cursor * pCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)779 vxpath_filter (sqlite3_vtab_cursor * pCursor, int idxNum, const char *idxStr,
780 int argc, sqlite3_value ** argv)
781 {
782 /* setting up a cursor filter */
783 int ok = 0;
784 VirtualXPathCursorPtr cursor = (VirtualXPathCursorPtr) pCursor;
785 if (idxStr)
786 idxStr = idxStr; /* unused arg warning suppression */
787 cursor->eof = 1;
788 if (idxNum == 1)
789 {
790 int i;
791 cursor->keyOp1 = 0;
792 cursor->keyOp2 = 0;
793 for (i = 0; i < argc; i++)
794 {
795 const char *pStr = idxStr + (i * 2);
796 if (*pStr == 0)
797 {
798 /* retrieving the XPath expression param */
799 if (sqlite3_value_type (argv[i]) == SQLITE_TEXT)
800 {
801 char *exp = (char *) sqlite3_value_text (argv[i]);
802 if (exp != NULL)
803 {
804 int len = strlen (exp);
805 cursor->xpathExpr = malloc (len + 1);
806 strcpy (cursor->xpathExpr, exp);
807 }
808 ok = 1;
809 }
810 }
811 else
812 {
813 /* evaluating a ROWID contraint */
814 pStr++;
815 if (cursor->keyOp1 == 0)
816 {
817 cursor->keyOp1 = *pStr;
818 cursor->keyVal1 = sqlite3_value_int64 (argv[i]);
819 }
820 else
821 {
822 cursor->keyOp2 = *pStr;
823 cursor->keyVal2 = sqlite3_value_int64 (argv[i]);
824 }
825 }
826 }
827 }
828 if (!ok)
829 {
830 cursor->eof = 1;
831 return SQLITE_OK;
832 }
833 /* attempting to set a reasonable ROWID */
834 switch (cursor->keyOp1)
835 {
836 case SQLITE_INDEX_CONSTRAINT_EQ:
837 cursor->current_row = cursor->keyVal1;
838 break;
839 case SQLITE_INDEX_CONSTRAINT_GT:
840 cursor->current_row = cursor->keyVal1 + 1;
841 break;
842 case SQLITE_INDEX_CONSTRAINT_GE:
843 cursor->current_row = cursor->keyVal1;
844 break;
845 };
846 switch (cursor->keyOp2)
847 {
848 case SQLITE_INDEX_CONSTRAINT_EQ:
849 cursor->current_row = cursor->keyVal2;
850 break;
851 case SQLITE_INDEX_CONSTRAINT_GT:
852 cursor->current_row = cursor->keyVal2 + 1;
853 break;
854 case SQLITE_INDEX_CONSTRAINT_GE:
855 cursor->current_row = cursor->keyVal2;
856 break;
857 };
858 vxpath_read_row (cursor);
859 return SQLITE_OK;
860 }
861
862 static int
vxpath_next(sqlite3_vtab_cursor * pCursor)863 vxpath_next (sqlite3_vtab_cursor * pCursor)
864 {
865 /* fetching a next row from cursor */
866 VirtualXPathCursorPtr cursor = (VirtualXPathCursorPtr) pCursor;
867 if (cursor->xpathObj != NULL)
868 {
869 /* we already have a current XPath node-set */
870 xmlNodeSetPtr nodes = cursor->xpathObj->nodesetval;
871 int num_nodes = (nodes) ? nodes->nodeNr : 0;
872 if ((cursor->xpathIdx + 1) < num_nodes)
873 {
874 /* ok, consuming the current XPath node from the node-set */
875 cursor->xpathIdx += 1;
876 return SQLITE_OK;
877 }
878 }
879 (cursor->current_row)++;
880 vxpath_read_row (cursor);
881 return SQLITE_OK;
882 }
883
884 static int
vxpath_eof(sqlite3_vtab_cursor * pCursor)885 vxpath_eof (sqlite3_vtab_cursor * pCursor)
886 {
887 /* cursor EOF */
888 VirtualXPathCursorPtr cursor = (VirtualXPathCursorPtr) pCursor;
889 return cursor->eof;
890 }
891
892 static int
vxpath_column(sqlite3_vtab_cursor * pCursor,sqlite3_context * pContext,int column)893 vxpath_column (sqlite3_vtab_cursor * pCursor, sqlite3_context * pContext,
894 int column)
895 {
896 /* fetching value for the Nth column */
897 VirtualXPathCursorPtr cursor = (VirtualXPathCursorPtr) pCursor;
898 xmlNodeSetPtr nodeset = cursor->xpathObj->nodesetval;
899 xmlNodePtr node = nodeset->nodeTab[cursor->xpathIdx];
900 xmlNodePtr parent = node->parent;
901 char *xParent = NULL;
902 char *xNode = NULL;
903 char *xAttribute = NULL;
904 char *xValue = NULL;
905 char *prefix;
906
907 if (node->type == XML_ELEMENT_NODE)
908 {
909 if (parent != NULL)
910 {
911 if (parent->ns != NULL && parent->name != NULL)
912 {
913 prefix = (char *) (parent->ns->prefix);
914 if (prefix == NULL)
915 prefix = "dflt";
916 xParent = sqlite3_mprintf ("%s:%s", prefix, parent->name);
917 }
918 else if (parent->name != NULL)
919 xParent = sqlite3_mprintf ("%s", parent->name);
920 }
921 if (node->ns != NULL && node->name != NULL)
922 {
923 prefix = (char *) (node->ns->prefix);
924 if (prefix == NULL)
925 prefix = "dflt";
926 xNode = sqlite3_mprintf ("%s:%s", prefix, node->name);
927 }
928 else if (node->name != NULL)
929 xNode = sqlite3_mprintf ("%s", node->name);
930 }
931 else if (node->type == XML_ATTRIBUTE_NODE)
932 {
933 if (parent != NULL)
934 {
935 xmlNodePtr granpa = parent->parent;
936 if (granpa != NULL)
937 {
938 if (granpa->ns != NULL && granpa->name != NULL)
939 {
940 prefix = (char *) (granpa->ns->prefix);
941 if (prefix == NULL)
942 prefix = "dflt";
943 xParent =
944 sqlite3_mprintf ("%s:%s", prefix, granpa->name);
945 }
946 else if (granpa->name != NULL)
947 xParent = sqlite3_mprintf ("%s", granpa->name);
948 }
949 if (parent->ns != NULL && parent->name != NULL)
950 {
951 prefix = (char *) (parent->ns->prefix);
952 if (prefix == NULL)
953 prefix = "dflt";
954 xNode = sqlite3_mprintf ("%s:%s", prefix, parent->name);
955 }
956 else if (parent->name != NULL)
957 xNode = sqlite3_mprintf ("%s", parent->name);
958 }
959 if (node->ns != NULL && node->name != NULL)
960 {
961 prefix = (char *) (node->ns->prefix);
962 if (prefix == NULL)
963 prefix = "dflt";
964 xAttribute = sqlite3_mprintf ("%s:%s", prefix, node->name);
965 }
966 else if (node->name != NULL)
967 xAttribute = sqlite3_mprintf ("%s", node->name);
968 if (node->children != NULL)
969 {
970 if (node->children->content != NULL)
971 xValue = sqlite3_mprintf ("%s", node->children->content);
972 }
973 }
974 else if (node->type == XML_TEXT_NODE)
975 {
976 if (parent != NULL)
977 {
978 xmlNodePtr granpa = parent->parent;
979 if (granpa != NULL)
980 {
981 if (granpa->ns != NULL && granpa->name != NULL)
982 {
983 prefix = (char *) (granpa->ns->prefix);
984 if (prefix == NULL)
985 prefix = "dflt";
986 xParent =
987 sqlite3_mprintf ("%s:%s", prefix, granpa->name);
988 }
989 else if (granpa->name != NULL)
990 xParent = sqlite3_mprintf ("%s", granpa->name);
991 }
992 if (parent->ns != NULL && parent->name != NULL)
993 {
994 prefix = (char *) (parent->ns->prefix);
995 if (prefix == NULL)
996 prefix = "dflt";
997 xNode = sqlite3_mprintf ("%s:%s", prefix, parent->name);
998 }
999 else if (parent->name != NULL)
1000 xNode = sqlite3_mprintf ("%s", parent->name);
1001 }
1002 if (node->content != NULL)
1003 xValue = sqlite3_mprintf ("%s", node->content);
1004 }
1005
1006 if (column == 0)
1007 sqlite3_result_int64 (pContext, cursor->current_row);
1008 else if (column == 1)
1009 sqlite3_result_int (pContext, cursor->xpathIdx);
1010 else if (column == 2)
1011 {
1012 if (!xParent)
1013 sqlite3_result_null (pContext);
1014 else
1015 sqlite3_result_text (pContext, xParent,
1016 strlen (xParent), SQLITE_TRANSIENT);
1017 }
1018 else if (column == 3)
1019 {
1020 if (!xNode)
1021 sqlite3_result_null (pContext);
1022 else
1023 sqlite3_result_text (pContext, xNode,
1024 strlen (xNode), SQLITE_TRANSIENT);
1025 }
1026 else if (column == 4)
1027 {
1028 if (!xAttribute)
1029 sqlite3_result_null (pContext);
1030 else
1031 sqlite3_result_text (pContext, xAttribute,
1032 strlen (xAttribute), SQLITE_TRANSIENT);
1033 }
1034 else if (column == 5)
1035 {
1036 if (!xValue)
1037 sqlite3_result_null (pContext);
1038 else
1039 sqlite3_result_text (pContext, xValue,
1040 strlen (xValue), SQLITE_TRANSIENT);
1041 }
1042 else if (column == 6)
1043 sqlite3_result_text (pContext, cursor->xpathExpr,
1044 strlen (cursor->xpathExpr), SQLITE_STATIC);
1045 else
1046 sqlite3_result_null (pContext);
1047 if (xParent)
1048 sqlite3_free (xParent);
1049 if (xNode)
1050 sqlite3_free (xNode);
1051 if (xAttribute)
1052 sqlite3_free (xAttribute);
1053 if (xValue)
1054 sqlite3_free (xValue);
1055 return SQLITE_OK;
1056 }
1057
1058 static int
vxpath_rowid(sqlite3_vtab_cursor * pCursor,sqlite_int64 * pRowid)1059 vxpath_rowid (sqlite3_vtab_cursor * pCursor, sqlite_int64 * pRowid)
1060 {
1061 /* fetching the ROWID */
1062 VirtualXPathCursorPtr cursor = (VirtualXPathCursorPtr) pCursor;
1063 *pRowid = cursor->current_row;
1064 return SQLITE_OK;
1065 }
1066
1067 static int
vxpath_update(sqlite3_vtab * pVTab,int argc,sqlite3_value ** argv,sqlite_int64 * pRowid)1068 vxpath_update (sqlite3_vtab * pVTab, int argc, sqlite3_value ** argv,
1069 sqlite_int64 * pRowid)
1070 {
1071 /* generic update [INSERT / UPDATE / DELETE */
1072 if (pRowid || argc || argv || pVTab)
1073 pRowid = pRowid; /* unused arg warning suppression */
1074 /* read only datasource */
1075 return SQLITE_READONLY;
1076 }
1077
1078 static int
vxpath_begin(sqlite3_vtab * pVTab)1079 vxpath_begin (sqlite3_vtab * pVTab)
1080 {
1081 /* BEGIN TRANSACTION */
1082 if (pVTab)
1083 pVTab = pVTab; /* unused arg warning suppression */
1084 return SQLITE_OK;
1085 }
1086
1087 static int
vxpath_sync(sqlite3_vtab * pVTab)1088 vxpath_sync (sqlite3_vtab * pVTab)
1089 {
1090 /* BEGIN TRANSACTION */
1091 if (pVTab)
1092 pVTab = pVTab; /* unused arg warning suppression */
1093 return SQLITE_OK;
1094 }
1095
1096 static int
vxpath_commit(sqlite3_vtab * pVTab)1097 vxpath_commit (sqlite3_vtab * pVTab)
1098 {
1099 /* BEGIN TRANSACTION */
1100 if (pVTab)
1101 pVTab = pVTab; /* unused arg warning suppression */
1102 return SQLITE_OK;
1103 }
1104
1105 static int
vxpath_rollback(sqlite3_vtab * pVTab)1106 vxpath_rollback (sqlite3_vtab * pVTab)
1107 {
1108 /* BEGIN TRANSACTION */
1109 if (pVTab)
1110 pVTab = pVTab; /* unused arg warning suppression */
1111 return SQLITE_OK;
1112 }
1113
1114 static int
vxpath_rename(sqlite3_vtab * pVTab,const char * zNew)1115 vxpath_rename (sqlite3_vtab * pVTab, const char *zNew)
1116 {
1117 /* BEGIN TRANSACTION */
1118 if (pVTab)
1119 pVTab = pVTab; /* unused arg warning suppression */
1120 if (zNew)
1121 zNew = zNew; /* unused arg warning suppression */
1122 return SQLITE_ERROR;
1123 }
1124
1125 static int
spliteVirtualXPathInit(sqlite3 * db,void * p_cache)1126 spliteVirtualXPathInit (sqlite3 * db, void *p_cache)
1127 {
1128 int rc = SQLITE_OK;
1129 my_xpath_module.iVersion = 1;
1130 my_xpath_module.xCreate = &vxpath_create;
1131 my_xpath_module.xConnect = &vxpath_connect;
1132 my_xpath_module.xBestIndex = &vxpath_best_index;
1133 my_xpath_module.xDisconnect = &vxpath_disconnect;
1134 my_xpath_module.xDestroy = &vxpath_destroy;
1135 my_xpath_module.xOpen = &vxpath_open;
1136 my_xpath_module.xClose = &vxpath_close;
1137 my_xpath_module.xFilter = &vxpath_filter;
1138 my_xpath_module.xNext = &vxpath_next;
1139 my_xpath_module.xEof = &vxpath_eof;
1140 my_xpath_module.xColumn = &vxpath_column;
1141 my_xpath_module.xRowid = &vxpath_rowid;
1142 my_xpath_module.xUpdate = &vxpath_update;
1143 my_xpath_module.xBegin = &vxpath_begin;
1144 my_xpath_module.xSync = &vxpath_sync;
1145 my_xpath_module.xCommit = &vxpath_commit;
1146 my_xpath_module.xRollback = &vxpath_rollback;
1147 my_xpath_module.xFindFunction = NULL;
1148 my_xpath_module.xRename = &vxpath_rename;
1149 sqlite3_create_module_v2 (db, "VirtualXPath", &my_xpath_module, p_cache, 0);
1150 return rc;
1151 }
1152
1153 SPATIALITE_PRIVATE int
virtual_xpath_extension_init(void * xdb,const void * p_cache)1154 virtual_xpath_extension_init (void *xdb, const void *p_cache)
1155 {
1156 sqlite3 *db = (sqlite3 *) xdb;
1157 return spliteVirtualXPathInit (db, (void *) p_cache);
1158 }
1159
1160 #endif /* end LIBXML2: supporting XML documents */
1161