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