1 /*
2  * Copyright 2006-2008 The FLWOR Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <iostream>
18 #include <fstream>
19 #include <sstream>
20 
21 #include <zorba/zorba.h>
22 #include <zorba/store_manager.h>
23 #include <zorba/uri_resolvers.h>
24 #include <zorba/xquery_exception.h>
25 
26 
27 using namespace zorba;
28 
29 /**
30  * Example to show the binding of external variables in the query context.
31  */
32 bool
context_example_1(Zorba * aZorba)33 context_example_1(Zorba* aZorba)
34 {
35   XQuery_t lQuery = aZorba->compileQuery("declare variable $var external; $var + $var");
36 
37   ItemFactory* lFactory = aZorba->getItemFactory();
38 
39   /* The item that is to be bound to the external variable */
40   Item lItem = lFactory->createInteger(4);
41 
42   DynamicContext* lCtx = lQuery->getDynamicContext();
43 
44   /* Actually perform the binding. */
45   lCtx->setVariable("var", lItem);
46 
47   try {
48 
49     std::cout << lQuery << std::endl;
50 
51   } catch (ZorbaException &e) {
52     std::cerr << e << std::endl;
53     return false;
54   }
55 
56   return true;
57 }
58 
59 /**
60  * Example showing an erroneous query that defines an external variable, but
61  * whose dynamic context does not bind any values to it.
62  * One needs to use the setVariable() call defined on the dynamic context
63  * in order to use external variables correctly.
64  */
65 bool
context_example_2(Zorba * aZorba)66 context_example_2(Zorba* aZorba)
67 {
68 	XQuery_t lQuery = aZorba->compileQuery("declare variable $var external; $var + $var");
69 
70   try {
71 
72     std::cout << lQuery << std::endl;
73 
74   } catch (ZorbaException &e) {
75     std::cerr << e << std::endl;
76     return true;
77   }
78 
79 	return false;
80 }
81 
82 /**
83  * Example to show the usage of the context item in a query. It is treated just as
84  * an external variable, except one uses the setContextItem() on the dynamic context
85  * to bind the value. It is an error to use a context item in a query but not bind it
86  * before execution.
87  */
88 bool
context_example_3(Zorba * aZorba)89 context_example_3(Zorba* aZorba)
90 {
91   XQuery_t lQuery = aZorba->compileQuery(".");
92 
93   ItemFactory* lFactory = aZorba->getItemFactory();
94 
95   Item lItem = lFactory->createInteger(4);
96 
97   DynamicContext* lCtx = lQuery->getDynamicContext();
98 
99   lCtx->setContextItem(lItem);
100 
101   try {
102 
103     std::cout << lQuery << std::endl;
104 
105   } catch (ZorbaException &e) {
106     std::cerr << e << std::endl;
107     return false;
108   }
109 
110 	return true;
111 }
112 
113 
114 /**
115  * Example to show the use of document content as the value of an external variable.
116  */
117 bool
context_example_4(Zorba * aZorba)118 context_example_4(Zorba* aZorba)
119 {
120   std::ostringstream outStream1;
121   std::ostringstream outStream2;
122 
123   std::auto_ptr<std::istream> lDocStream1(
124     new std::stringstream("<books><book>Book 1</book><book>Book 2</book></books>"));
125 
126   std::auto_ptr<std::istream> lDocStream2(
127     new std::stringstream("<books><book>Book 1.1</book><book>Book 2.2</book></books>"));
128 
129   try
130   {
131     XQuery_t lQuery = aZorba->compileQuery("declare variable $doc external; $doc//book[1]/text()");
132 
133     DynamicContext* lCtx = lQuery->getDynamicContext();
134 
135     // Parses the input stream and internally creates a datamodel instance
136     // that can be bound to the variable.
137     XmlDataManager* lXmlMgr = aZorba->getXmlDataManager();
138     Item lDoc = lXmlMgr->parseXML(*lDocStream1);
139 
140     lCtx->setVariable("doc", lDoc);
141 
142     outStream1 << lQuery << std::endl;
143     std::cout << outStream1.str() << std::endl;
144 
145     // Reset the value of the $doc variable to the 2nd document.
146     lDoc = lXmlMgr->parseXML(*lDocStream2);
147     lCtx->setVariable("doc", lDoc);
148 
149     outStream2 << lQuery << std::endl;
150     std::cout << outStream2.str() << std::endl;
151 
152 #ifndef ZORBA_NO_ICU
153     if (outStream2.str() != "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\nBook 1.1\n")
154 #else
155     if (outStream2.str() != "<?xml version=\"1.0\"?>\nBook 1.1\n")
156 #endif /* ZORBA_NO_ICU */
157     {
158       std::cerr << "Test 4 failed with a wrong result : " << std::endl
159                 << outStream2.str() << std::endl;
160       return false;
161     }
162   }
163   catch (ZorbaException& e)
164   {
165     std::cerr << "Test 4 failed with exception : " << e << std::endl;
166     return false;
167   }
168   catch (...)
169   {
170     std::cerr << "Test 4 failed with unknown exception" << std::endl;
171     return false;
172   }
173 
174   return true;
175 }
176 
177 
178 /**
179  * Example to show the use of document content as the value of the context item in
180  * a query.
181  */
182 bool
context_example_5(Zorba * aZorba)183 context_example_5(Zorba* aZorba)
184 {
185 
186   std::auto_ptr<std::istream> lDocStream(
187     new std::stringstream("<books><book>Book 1</book><book>Book 2</book></books>"));
188 
189   XQuery_t lQuery = aZorba->compileQuery("declare variable $var external; .//book");
190 
191   DynamicContext* lCtx = lQuery->getDynamicContext();
192   XmlDataManager* lXmlMgr = aZorba->getXmlDataManager();
193   Item lDoc = lXmlMgr->parseXML(*lDocStream);
194   lCtx->setContextItem(lDoc);
195 
196   try {
197     std::cout << lQuery << std::endl;
198   } catch (ZorbaException& e) {
199     std::cerr << e << std::endl;
200     return false;
201   }
202   return true;
203 }
204 
205 /**
206  * Example to show the use of collations in string comparison.
207  */
208 bool
context_example_6(Zorba * aZorba)209 context_example_6(Zorba* aZorba)
210 {
211   StaticContext_t lStaticContext = aZorba->createStaticContext();
212 
213   /* Add the German collation to the context */
214   lStaticContext->addCollation("http://www.zorba-xquery.com/collations/PRIMARY/de/DE");
215 
216   lStaticContext->setBaseURI("http://www.zorba-xquery.com/");
217 
218   if ( lStaticContext->getBaseURI() != "http://www.zorba-xquery.com/")
219     return false;
220 
221   /* Use the German collation as the third argument to the fn:compare() XQuery function */
222   XQuery_t lQuery = aZorba->compileQuery("fn:compare('Strasse', 'Stra??e', 'http://www.zorba-xquery.com/collations/PRIMARY/de/DE')",
223           lStaticContext);
224 
225   try {
226 
227     std::cout << lQuery << std::endl;
228 
229   } catch (ZorbaException &e) {
230     std::cerr << e << std::endl;
231     return false;
232   }
233 
234 	return true;
235 }
236 
237 /**
238  * Example to show the erroneous use of incorrect collation URIs in Zorba.
239  */
240 bool
context_example_7(Zorba * aZorba)241 context_example_7(Zorba* aZorba)
242 {
243   StaticContext_t lStaticContext = aZorba->createStaticContext();
244 
245   try {
246     lStaticContext->addCollation("http://www.zorba-xquery.com/zorba/collations/PRIMARY");
247 
248     XQuery_t lQuery = aZorba->compileQuery("fn:compare('Strasse', 'Stra??e', 'http://www.zorba-xquery.com/zorba/collations/PRIMARY')",
249         lStaticContext);
250 
251     std::cout << lQuery << std::endl;
252 
253   } catch (XQueryException &e) {
254     std::cerr << e << std::endl;
255     return true;
256   }
257 
258 	return false;
259 }
260 
261 /**
262  * Example to show the connection between the ordering mode as defined in the query
263  * prolog and that in the context of the query.
264  */
265 bool
context_example_8(Zorba * aZorba)266 context_example_8(Zorba* aZorba)
267 {
268   /* The query sets the ordering mode to ordered */
269   XQuery_t lQuery1 = aZorba->compileQuery("declare ordering ordered; 1");
270 
271   const StaticContext* lStaticContext1 = lQuery1->getStaticContext();
272 
273   /* Programmatically the effect can be observed in the context */
274   if (lStaticContext1->getOrderingMode() != ordered)
275     return false;
276 
277   XQuery_t lQuery2 = aZorba->compileQuery("declare ordering unordered; 1");
278 
279   const StaticContext* lStaticContext2 = lQuery2->getStaticContext();
280 
281   return (lStaticContext2->getOrderingMode() == unordered);
282 }
283 
284 /**
285  * Example to show the ability to define the current dateTime in the dynamic context.
286  */
287 bool
context_example_9(Zorba * aZorba)288 context_example_9(Zorba* aZorba)
289 {
290 	XQuery_t lQuery = aZorba->compileQuery("fn:hours-from-dateTime(fn:current-dateTime())");
291 
292   DynamicContext* lDynContext = lQuery->getDynamicContext();
293 
294   try {
295     Item lDateTimeItem = aZorba->getItemFactory()->createDateTime(2008, 03, 30, 16, 05, 42, 0);
296 
297     lDynContext->setCurrentDateTime(lDateTimeItem);
298     std::cout << lQuery << std::endl;
299   }
300   catch (ZorbaException& e)
301   {
302     std::cerr << e << std::endl;
303     return false;
304   }
305 
306 	return true;
307 }
308 
309 /**
310  * Example to show the findFunctions function of the static context
311  */
312 bool
context_example_10(Zorba * aZorba)313 context_example_10(Zorba* aZorba)
314 {
315   StaticContext_t lContext = aZorba->createStaticContext();
316 
317   try
318   {
319     Item lQName = aZorba->getItemFactory()->createQName("http://www.w3.org/2005/xpath-functions", "doc");
320 
321     std::vector<Function_t> lFunctions;
322     lContext->findFunctions(lQName, lFunctions);
323 
324     std::cout << "Number of Functions " << lFunctions.size() << std::endl;
325 
326     for (std::vector<Function_t>::const_iterator lIter = lFunctions.begin();
327          lIter != lFunctions.end(); ++lIter)
328     {
329       std::cout << "Function Name " << (*lIter)->getQName().getStringValue() << std::endl;
330       //std::cout << "  requires dynamic context " << (*lIter)->requiresDynamicContext() << std::endl;
331       std::cout << "  is updating " << (*lIter)->isUpdating() << std::endl;
332       std::cout << "  arity " << (*lIter)->getArity() << std::endl;
333 
334       lContext->disableFunction(*lIter);
335     }
336 
337     try
338     {
339       XQuery_t lQuery = aZorba->compileQuery("fn:doc('test.xml')", lContext);
340     }
341     catch (ZorbaException const &se)
342     {
343       std::cerr << se << std::endl;
344       return true;
345     }
346   }
347   catch (ZorbaException &e)
348   {
349     std::cerr << e << std::endl;
350     return false;
351   }
352 
353 	return false;
354 }
355 
356 static void
releaseStream(std::istream * aStream)357 releaseStream(std::istream* aStream)
358 {
359   delete aStream;
360 }
361 
362 class PrologModuleURLResolver : public URLResolver
363 {
364 public:
~PrologModuleURLResolver()365   virtual ~PrologModuleURLResolver() {}
366 
resolveURL(const String & aUrl,EntityData const * aEntityData)367   virtual Resource* resolveURL(
368         const String& aUrl,
369         EntityData const* aEntityData)
370   {
371     if (aEntityData->getKind() == EntityData::MODULE &&
372       aUrl == "http://www.zorba-xquery.com/mymodule")
373     {
374       // we have only one module
375       std::auto_ptr<std::stringstream> lQuery(new std::stringstream());
376       (*lQuery)
377         << "module namespace mymodule = 'http://www.zorba-xquery.com/mymodule';" << std::endl
378         << "import module namespace dml = 'http://www.zorba-xquery.com/modules/store/static/collections/dml';" << std::endl
379         << "declare namespace an = 'http://www.zorba-xquery.com/annotations';" << std::endl
380         << "declare variable $mymodule:var  := 'myvar';" << std::endl
381         << "declare collection mymodule:collection;" << std::endl
382         << "declare %an:automatic %an:value-equality index mymodule:index" << std::endl
383         << "  on nodes dml:collection(xs:QName('mymodule:collection'))" << std::endl
384         << "  by ./foo as xs:string;" << std::endl;
385       return StreamResource::create(lQuery.release(), &releaseStream);
386     }
387     else {
388       return NULL;
389     }
390   }
391 };
392 
393 /**
394  * test to demonstrate the loadProlog functionality that uses
395  * a query to populate a static context.
396  * The resulting context is used in order to compile another
397  * (main) query.
398  * The prolog contains a variable, a collection, and a function
399  * declaration.
400  */
401 bool
context_example_11(Zorba * aZorba)402 context_example_11(Zorba* aZorba)
403 {
404   StaticContext_t lContext = aZorba->createStaticContext();
405   PrologModuleURLResolver lResolver;
406   lContext->registerURLResolver(&lResolver);
407 
408   try {
409     Zorba_CompilerHints_t hints;
410     std::stringstream lProlog;
411     lProlog << "import module namespace mymodule = 'http://www.zorba-xquery.com/mymodule';" << std::endl
412             << "import module namespace ddl = 'http://www.zorba-xquery.com/modules/store/static/collections/ddl';"
413             << std::endl
414             << "declare function local:collections() { " << std::endl
415             << "  ddl:declared-collections()" << std::endl
416             << "};" << std::endl;
417     lContext->loadProlog(lProlog.str(), hints);
418 
419     // compile the main query using the populated static context
420     XQuery_t lQuery = aZorba->compileQuery("$mymodule:var, local:collections()", lContext);
421 
422     // execute the query and make sure that the result is correct
423     Zorba_SerializerOptions lSerOptions;
424     lSerOptions.omit_xml_declaration = ZORBA_OMIT_XML_DECLARATION_YES;
425     std::stringstream lResult;
426     lQuery->execute(lResult, &lSerOptions);
427     std::cout << "result " << lResult.str() << std::endl;
428 
429     if (lResult.str().compare("myvar mymodule:collection") == 0) {
430       return true;
431     } else {
432       std::cerr << "result doesn't match expected result (myvar mymodule:collection)"
433                 << std::endl;
434       return false;
435     }
436 
437   } catch (XQueryException &e) {
438     std::cerr << e << std::endl;
439     return false;
440   }
441 	return false;
442 }
443 
444 bool
context_example_12(Zorba * aZorba)445 context_example_12(Zorba* aZorba)
446 {
447   std::ostringstream lTraceStream;
448 
449   StaticContext_t lContext = aZorba->createStaticContext();
450 
451   Item lTraceQName = aZorba->getItemFactory()->createQName("http://www.zorba-xquery.org/options", "trace");
452   lContext->declareOption(lTraceQName, "enable");
453   lContext->setTraceStream(lTraceStream);
454 
455   try {
456     Zorba_CompilerHints_t hints;
457 
458     XQuery_t aQuery = aZorba->compileQuery("fn:trace(1 to 3, 'foo')", lContext);
459 
460     // execute the query
461     std::cout << aQuery << std::endl;
462 
463     // check if the trace was successful
464     std::string lTraceString = lTraceStream.str();
465     std::cout << lTraceString << std::endl;
466     if (lTraceString.compare("foo [1]: 1\n"
467           "foo [2]: 2\n"
468           "foo [3]: 3\n") != 0) {
469       return false;
470     }
471     std::cout << lTraceString << std::endl;
472     return true;
473 
474   } catch (XQueryException &e) {
475     std::cerr << e << std::endl;
476     return false;
477   }
478 
479 	return false;
480 }
481 
482 struct callback_data
483 {
484   bool b;
485 };
486 
487 int
context(int argc,char * argv[])488 context(int argc, char* argv[])
489 {
490   void* lStore = zorba::StoreManager::getStore();
491 
492   Zorba* lZorba = Zorba::getInstance(lStore);
493   bool res = false;
494 
495   std::cout << "executing example 1" << std::endl;
496   res = context_example_1(lZorba);
497   if (!res) return 1;
498   std::cout << std::endl;
499 
500   std::cout << "executing example 2" << std::endl;
501   res = context_example_2(lZorba);
502   if (!res) return 1;
503   std::cout << std::endl;
504 
505   std::cout << "executing example 3" << std::endl;
506   res = context_example_3(lZorba);
507   if (!res) return 1;
508   std::cout << std::endl;
509 
510   std::cout << "executing example 4" << std::endl;
511   res = context_example_4(lZorba);
512   if (!res) return 1;
513   std::cout << std::endl;
514 
515   std::cout << "executing example 5" << std::endl;
516   res = context_example_5(lZorba);
517   if (!res) return 1;
518   std::cout << std::endl;
519 
520   std::cout << "executing example 6" << std::endl;
521   res = context_example_6(lZorba);
522   if (!res) return 1;
523   std::cout << std::endl;
524 
525   std::cout << "executing example 7" << std::endl;
526   res = context_example_7(lZorba);
527   if (!res) return 1;
528   std::cout << std::endl;
529 
530   std::cout << "executing example_8" << std::endl;
531   res = context_example_8(lZorba);
532   if (!res) return 1;
533   std::cout << std::endl;
534 
535   std::cout << "executing example_9" << std::endl;
536   res = context_example_9(lZorba);
537   if (!res) return 1;
538   std::cout << std::endl;
539 
540   std::cout << "executing example_10" << std::endl;
541   res = context_example_10(lZorba);
542   if (!res) return 1;
543   std::cout << std::endl;
544 
545   std::cout << "executing example_11" << std::endl;
546   res = context_example_11(lZorba);
547   if (!res) return 1;
548   std::cout << std::endl;
549 
550   std::cout << "executing example_12" << std::endl;
551   res = context_example_12(lZorba);
552   if (!res) return 1;
553   std::cout << std::endl;
554 
555   lZorba->shutdown();
556   zorba::StoreManager::shutdownStore(lStore);
557   return 0;
558 }
559