Checkout submodules as necessary MPSPARQL-23
[mp-sparql-moved-to-github.git] / src / test_sparql.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 #if HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8
9 #include <string.h>
10 #include "sparql.h"
11 #include <yaz/log.h>
12 #include <yaz/test.h>
13 #include <yaz/pquery.h>
14
15 static int test_query(yaz_sparql_t s, const char *pqf, const char *expect)
16 {
17     YAZ_PQF_Parser parser = yaz_pqf_create();
18     ODR odr = odr_createmem(ODR_ENCODE);
19     Z_RPNQuery *rpn = yaz_pqf_parse(parser, odr, pqf);
20     int ret = 0;
21     WRBUF addinfo = wrbuf_alloc();
22     WRBUF w = wrbuf_alloc();
23
24     if (rpn)
25     {
26         int r = yaz_sparql_from_rpn_wrbuf(s, addinfo, w, rpn);
27         if (expect)
28         {
29             if (!r)
30             {
31                 if (!strcmp(expect, wrbuf_cstr(w)))
32                     ret = 1;
33                 else
34                 {
35                     yaz_log(YLOG_WARN, "test_sparql: pqf=%s", pqf);
36                     yaz_log(YLOG_WARN, " expect: %s", expect);
37                     yaz_log(YLOG_WARN, " got:    %s", wrbuf_cstr(w));
38                 }
39             }
40             else
41             {
42                 yaz_log(YLOG_WARN, "test_sparql: pqf=%s", pqf);
43                 yaz_log(YLOG_WARN, " expect: %s", expect);
44                 yaz_log(YLOG_WARN, " got error: %d:%s", r, wrbuf_cstr(addinfo));
45             }
46         }
47         else
48         {
49             if (r)
50                 ret = 1;
51             else
52             {
53                 yaz_log(YLOG_WARN, "test_sparql: pqf=%s", pqf);
54                 yaz_log(YLOG_WARN, " expect error");
55                 yaz_log(YLOG_WARN, " got:    %s", wrbuf_cstr(w));
56             }
57         }
58     }
59     wrbuf_destroy(w);
60     wrbuf_destroy(addinfo);
61     odr_destroy(odr);
62     yaz_pqf_destroy(parser);
63     return ret;
64 }
65
66 static int test_uri(yaz_sparql_t s, const char *uri, const char *schema,
67                     const char *expect)
68 {
69     int ret = 0;
70     WRBUF addinfo = wrbuf_alloc();
71     WRBUF w = wrbuf_alloc();
72
73     int r = yaz_sparql_from_uri_wrbuf(s, addinfo, w, uri, schema);
74     if (expect)
75     {
76         if (!r)
77         {
78             if (!strcmp(expect, wrbuf_cstr(w)))
79                 ret = 1;
80             else
81             {
82                 yaz_log(YLOG_WARN, "test_sparql: uri=%s", uri);
83                 yaz_log(YLOG_WARN, " expect: %s", expect);
84                 yaz_log(YLOG_WARN, " got:    %s", wrbuf_cstr(w));
85             }
86         }
87         else
88         {
89             yaz_log(YLOG_WARN, "test_sparql: uri=%s", uri);
90             yaz_log(YLOG_WARN, " expect: %s", expect);
91             yaz_log(YLOG_WARN, " got error: %d:%s", r, wrbuf_cstr(addinfo));
92         }
93     }
94     else
95     {
96         if (r)
97             ret = 1;
98         else
99         {
100             yaz_log(YLOG_WARN, "test_sparql: uri=%s", uri);
101             yaz_log(YLOG_WARN, " expect error");
102             yaz_log(YLOG_WARN, " got:    %s", wrbuf_cstr(w));
103         }
104     }
105     wrbuf_destroy(w);
106     wrbuf_destroy(addinfo);
107     return ret;
108 }
109
110
111 static void tst1(void)
112 {
113     yaz_sparql_t s = yaz_sparql_create();
114
115     yaz_sparql_add_pattern(s, "prefix",
116                            "rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns");
117     yaz_sparql_add_pattern(s, "prefix",
118                            "bf: <http://bibframe.org/vocab/>");
119     yaz_sparql_add_pattern(s, "prefix",
120                            "gs: http://gs.com/panorama/domain-model");
121     yaz_sparql_add_pattern(s, "form", "SELECT ?title ?author ?description ?ititle");
122     yaz_sparql_add_pattern(s, "criteria", "?work a bf:Work");
123     yaz_sparql_add_pattern(s, "criteria", "?work bf:workTitle/bf:titleValue ?title");
124     yaz_sparql_add_pattern(s, "criteria", "?work bf:creator/bf:label ?author");
125     yaz_sparql_add_pattern(s, "criteria", "?work bf:note ?description");
126     yaz_sparql_add_pattern(s, "criteria", "?inst bf:instanceOf ?work");
127     yaz_sparql_add_pattern(s, "criteria", "?inst bf:instanceTitle/bf:titleValue ?ititle");
128     yaz_sparql_add_pattern(s, "criteria.optional", "?inst bf:heldBy ?lib");
129
130     yaz_sparql_add_pattern(s, "index.bf.title",
131                            "?work bf:workTitle/bf:titleValue ?o1 "
132                            "FILTER(contains(?o1, %s))");
133     yaz_sparql_add_pattern(s, "index.bf.creator",
134                            "?work bf:creator/bf:label ?o2 "
135                            "FILTER(contains(?o2, %s))");
136     yaz_sparql_add_pattern(s, "index.bf.authorityCreator",
137                            "?work bf:author %s");
138     yaz_sparql_add_pattern(s, "index.bf.type",
139                            "?inst rdf:type %s");
140     yaz_sparql_add_pattern(s, "index.bf.format",
141                            "?inst bf:format ?o5 FILTER(contains(?o5, %s))");
142     yaz_sparql_add_pattern(s, "index.bf.nearby", "?lib gs:nearby (%d)");
143     yaz_sparql_add_pattern(s, "index.bf.baseTitle",
144                            "?work bf:derivativeOf/bf:workTitle/bf:titleValue "
145                            "?o6 FILTER(contains(?o6, %s))");
146     yaz_sparql_add_pattern(s, "index.bf.baseCreator",
147                            "?work bf:derivativeOf/bf:creator/bf:label "
148                            "?o7 FILTER(contains(?o7, %s))");
149     yaz_sparql_add_pattern(s, "index.bf.targetAudience",
150                            "?work bf:targetAudience %s");
151     yaz_sparql_add_pattern(s, "index.bf.isbn", "?inst bf:ISBN %s");
152
153     yaz_sparql_add_pattern(s, "uri.full", "SELECT ?sub ?rel WHERE ?work = %u");
154     yaz_sparql_add_pattern(s, "present.brief", "SELECT %u");
155
156     YAZ_CHECK(test_uri(s, "http://x/y", "full",
157                        "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
158                        "PREFIX bf: <http://bibframe.org/vocab/>\n"
159                        "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
160                        "SELECT ?sub ?rel WHERE ?work = <http://x/y>\n"));
161
162
163     YAZ_CHECK(test_uri(s, "http://x/z", "brief",
164                        "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
165                        "PREFIX bf: <http://bibframe.org/vocab/>\n"
166                        "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
167                        "SELECT <http://x/z>\n"));
168
169     YAZ_CHECK(test_query(
170                   s, "@attr 1=bf.title computer",
171                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
172                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
173                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
174                   "SELECT ?title ?author ?description ?ititle\n"
175                   "WHERE {\n"
176                   "  ?work a bf:Work .\n"
177                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
178                   "  ?work bf:creator/bf:label ?author .\n"
179                   "  ?work bf:note ?description .\n"
180                   "  ?inst bf:instanceOf ?work .\n"
181                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
182                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
183                   "  ?work bf:workTitle/bf:titleValue ?o1 "
184                   "FILTER(contains(?o1, \"computer\"))\n"
185                   "}\n"
186                   ));
187
188     YAZ_CHECK(test_query(
189                   s, "@attr 1=bf.creator london",
190                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
191                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
192                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
193                   "SELECT ?title ?author ?description ?ititle\n"
194                   "WHERE {\n"
195                   "  ?work a bf:Work .\n"
196                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
197                   "  ?work bf:creator/bf:label ?author .\n"
198                   "  ?work bf:note ?description .\n"
199                   "  ?inst bf:instanceOf ?work .\n"
200                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
201                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
202                   "  ?work bf:creator/bf:label ?o2 "
203                   "FILTER(contains(?o2, \"london\"))\n"
204                   "}\n"));
205
206
207     YAZ_CHECK(test_query(
208                   s, "@and @attr 1=bf.creator london @attr 1=bf.title computer",
209                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
210                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
211                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
212                   "SELECT ?title ?author ?description ?ititle\n"
213                   "WHERE {\n"
214                   "  ?work a bf:Work .\n"
215                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
216                   "  ?work bf:creator/bf:label ?author .\n"
217                   "  ?work bf:note ?description .\n"
218                   "  ?inst bf:instanceOf ?work .\n"
219                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
220                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
221                   "  ?work bf:creator/bf:label ?o2 "
222                   "FILTER(contains(?o2, \"london\")) .\n"
223                   "  ?work bf:workTitle/bf:titleValue ?o1 "
224                   "FILTER(contains(?o1, \"computer\"))\n"
225                   "}\n"));
226
227     YAZ_CHECK(test_query(
228                   s, "@or @attr 1=bf.creator london @attr 1=bf.title computer",
229                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
230                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
231                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
232                   "SELECT ?title ?author ?description ?ititle\n"
233                   "WHERE {\n"
234                   "  ?work a bf:Work .\n"
235                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
236                   "  ?work bf:creator/bf:label ?author .\n"
237                   "  ?work bf:note ?description .\n"
238                   "  ?inst bf:instanceOf ?work .\n"
239                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
240                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
241                   "  {\n"
242                   "   ?work bf:creator/bf:label ?o2 "
243                   "FILTER(contains(?o2, \"london\"))\n"
244                   "  } UNION {\n"
245                   "   ?work bf:workTitle/bf:titleValue ?o1 "
246                   "FILTER(contains(?o1, \"computer\"))\n"
247                   "  }\n"
248                   "}\n"
249                   ));
250
251     YAZ_CHECK(test_query(
252                   s, "@or @or @attr 1=bf.creator a @attr 1=bf.title b @attr 1=bf.title c",
253                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
254                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
255                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
256                   "SELECT ?title ?author ?description ?ititle\n"
257                   "WHERE {\n"
258                   "  ?work a bf:Work .\n"
259                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
260                   "  ?work bf:creator/bf:label ?author .\n"
261                   "  ?work bf:note ?description .\n"
262                   "  ?inst bf:instanceOf ?work .\n"
263                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
264                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
265                   "  {\n"
266                   "   {\n"
267                   "    ?work bf:creator/bf:label ?o2 "
268                   "FILTER(contains(?o2, \"a\"))\n"
269                   "   } UNION {\n"
270                   "    ?work bf:workTitle/bf:titleValue ?o1 "
271                   "FILTER(contains(?o1, \"b\"))\n"
272                   "   }\n"
273                   "  } UNION {\n"
274                   "   ?work bf:workTitle/bf:titleValue ?o1 "
275                   "FILTER(contains(?o1, \"c\"))\n"
276                   "  }\n"
277                   "}\n"
278                   ));
279
280     YAZ_CHECK(test_query(
281                   s, "@or @and @attr 1=bf.creator a @attr 1=bf.title b @attr 1=bf.title c",
282                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
283                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
284                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
285                   "SELECT ?title ?author ?description ?ititle\n"
286                   "WHERE {\n"
287                   "  ?work a bf:Work .\n"
288                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
289                   "  ?work bf:creator/bf:label ?author .\n"
290                   "  ?work bf:note ?description .\n"
291                   "  ?inst bf:instanceOf ?work .\n"
292                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
293                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
294                   "  {\n"
295                   "   ?work bf:creator/bf:label ?o2 "
296                   "FILTER(contains(?o2, \"a\")) .\n"
297                   "   ?work bf:workTitle/bf:titleValue ?o1 "
298                   "FILTER(contains(?o1, \"b\"))\n"
299                   "  } UNION {\n"
300                   "   ?work bf:workTitle/bf:titleValue ?o1 "
301                   "FILTER(contains(?o1, \"c\"))\n"
302                   "  }\n"
303                   "}\n"
304                   ));
305
306     YAZ_CHECK(test_query(
307                   s, "@and @and @attr 1=bf.creator a @attr 1=bf.title b @attr 1=bf.title c",
308                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
309                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
310                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
311                   "SELECT ?title ?author ?description ?ititle\n"
312                   "WHERE {\n"
313                   "  ?work a bf:Work .\n"
314                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
315                   "  ?work bf:creator/bf:label ?author .\n"
316                   "  ?work bf:note ?description .\n"
317                   "  ?inst bf:instanceOf ?work .\n"
318                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
319                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
320                   "  ?work bf:creator/bf:label ?o2 "
321                   "FILTER(contains(?o2, \"a\")) .\n"
322                   "  ?work bf:workTitle/bf:titleValue ?o1 "
323                   "FILTER(contains(?o1, \"b\")) .\n"
324                   "  ?work bf:workTitle/bf:titleValue ?o1 "
325                   "FILTER(contains(?o1, \"c\"))\n"
326                   "}\n"
327                   ));
328
329     YAZ_CHECK(test_query(
330                   s, "@and @attr 1=bf.title \"Phantom Tollbooth\" "
331                   "@attr 1=bf.nearby \"40.1583 83.0742 30\"",
332                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
333                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
334                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
335                   "SELECT ?title ?author ?description ?ititle\n"
336                   "WHERE {\n"
337                   "  ?work a bf:Work .\n"
338                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
339                   "  ?work bf:creator/bf:label ?author .\n"
340                   "  ?work bf:note ?description .\n"
341                   "  ?inst bf:instanceOf ?work .\n"
342                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
343                   "  ?inst bf:heldBy ?lib .\n"
344                   "  ?work bf:workTitle/bf:titleValue ?o1 "
345                   "FILTER(contains(?o1, \"Phantom Tollbooth\")) .\n"
346                   "  ?lib gs:nearby (40.1583 83.0742 30)\n"
347                   "}\n"
348                   ));
349
350     YAZ_CHECK(test_query(
351                   s, "@attr 1=bf.isbn 9780316154697",
352                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
353                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
354                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
355                   "SELECT ?title ?author ?description ?ititle\n"
356                   "WHERE {\n"
357                   "  ?work a bf:Work .\n"
358                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
359                   "  ?work bf:creator/bf:label ?author .\n"
360                   "  ?work bf:note ?description .\n"
361                   "  ?inst bf:instanceOf ?work .\n"
362                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
363                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
364                   "  ?inst bf:ISBN \"9780316154697\"\n"
365                   "}\n"
366                  ));
367
368
369     yaz_sparql_destroy(s);
370 }
371
372 static void tst2(void)
373 {
374     yaz_sparql_t s = yaz_sparql_create();
375     yaz_sparql_t s2 = yaz_sparql_create();
376
377     yaz_sparql_add_pattern(s, "prefix",
378                            "rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns");
379     yaz_sparql_add_pattern(s, "prefix",
380                            "bf: <http://bibframe.org/vocab/>");
381     yaz_sparql_add_pattern(s, "prefix",
382                            "gs: http://gs.com/panorama/domain-model");
383     yaz_sparql_add_pattern(s, "form", "SELECT ?title ?author ?description ?ititle");
384     yaz_sparql_add_pattern(s, "criteria", "?work a bf:Work");
385     yaz_sparql_add_pattern(s, "criteria", "?work bf:workTitle/bf:titleValue ?title");
386     yaz_sparql_add_pattern(s, "criteria", "?work bf:creator/bf:label ?author");
387     yaz_sparql_add_pattern(s, "criteria", "?work bf:note ?description");
388     yaz_sparql_add_pattern(s, "criteria", "?inst bf:instanceOf ?work");
389     yaz_sparql_add_pattern(s, "criteria", "?inst bf:instanceTitle/bf:titleValue ?ititle");
390     yaz_sparql_add_pattern(s, "criteria.optional", "?inst bf:heldBy ?lib");
391
392     yaz_sparql_add_pattern(s, "index.bf.title",
393                            "?work bf:workTitle/bf:titleValue %v "
394                            "FILTER(contains(%v, %s))");
395     yaz_sparql_add_pattern(s, "index.bf.creator",
396                            "?work bf:creator/bf:label %v "
397                            "FILTER(contains(%v, %s))");
398     yaz_sparql_add_pattern(s, "index.bf.authorityCreator",
399                            "?work bf:author %s");
400     yaz_sparql_add_pattern(s, "index.bf.type", "?inst rdf:type %s");
401     yaz_sparql_add_pattern(s, "index.bf.format",
402                            "?inst bf:format %v FILTER(contains(%v, %s))");
403     yaz_sparql_add_pattern(s, "index.bf.nearby", "?lib gs:nearby (%d)");
404     yaz_sparql_add_pattern(s, "index.bf.baseTitle",
405                            "?work bf:derivativeOf/bf:workTitle/bf:titleValue "
406                            "%v FILTER(contains(%v, %s))");
407     yaz_sparql_add_pattern(s, "index.bf.baseCreator",
408                            "?work bf:derivativeOf/bf:creator/bf:label "
409                            "%v FILTER(contains(%v, %s))");
410     yaz_sparql_add_pattern(s, "index.bf.targetAudience",
411                            "?work bf:targetAudience %s");
412     yaz_sparql_add_pattern(s, "index.bf.isbn", "?inst bf:ISBN %s");
413
414     YAZ_CHECK(test_query(
415                   s, "@attr 1=bf.title computer",
416                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
417                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
418                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
419                   "SELECT ?title ?author ?description ?ititle\n"
420                   "WHERE {\n"
421                   "  ?work a bf:Work .\n"
422                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
423                   "  ?work bf:creator/bf:label ?author .\n"
424                   "  ?work bf:note ?description .\n"
425                   "  ?inst bf:instanceOf ?work .\n"
426                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
427                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
428                   "  ?work bf:workTitle/bf:titleValue ?v0 "
429                   "FILTER(contains(?v0, \"computer\"))\n"
430                   "}\n"
431                   ));
432
433     YAZ_CHECK(test_query(
434                   s, "@attr 1=bf.creator london",
435                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
436                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
437                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
438                   "SELECT ?title ?author ?description ?ititle\n"
439                   "WHERE {\n"
440                   "  ?work a bf:Work .\n"
441                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
442                   "  ?work bf:creator/bf:label ?author .\n"
443                   "  ?work bf:note ?description .\n"
444                   "  ?inst bf:instanceOf ?work .\n"
445                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
446                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
447                   "  ?work bf:creator/bf:label ?v0 "
448                   "FILTER(contains(?v0, \"london\"))\n"
449
450
451                   "}\n"));
452
453     yaz_sparql_include(s2, s);
454
455     YAZ_CHECK(test_query(
456                   s2, "@or @and @attr 1=bf.creator a @attr 1=bf.title b @attr 1=bf.title c",
457                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
458                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
459                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
460                   "SELECT ?title ?author ?description ?ititle\n"
461                   "WHERE {\n"
462                   "  ?work a bf:Work .\n"
463                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
464                   "  ?work bf:creator/bf:label ?author .\n"
465                   "  ?work bf:note ?description .\n"
466                   "  ?inst bf:instanceOf ?work .\n"
467                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
468                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
469                   "  {\n"
470                   "   ?work bf:creator/bf:label ?v0 "
471                   "FILTER(contains(?v0, \"a\")) .\n"
472                   "   ?work bf:workTitle/bf:titleValue ?v1 "
473                   "FILTER(contains(?v1, \"b\"))\n"
474                   "  } UNION {\n"
475                   "   ?work bf:workTitle/bf:titleValue ?v2 "
476                   "FILTER(contains(?v2, \"c\"))\n"
477                   "  }\n"
478                   "}\n"
479                   ));
480
481     yaz_sparql_destroy(s2);
482     yaz_sparql_destroy(s);
483 }
484
485 int main(int argc, char **argv)
486 {
487     YAZ_CHECK_INIT(argc, argv);
488     YAZ_CHECK_LOG();
489     tst1();
490     tst2();
491     YAZ_CHECK_TERM;
492 }
493 /*
494  * Local variables:
495  * c-basic-offset: 4
496  * c-file-style: "Stroustrup"
497  * indent-tabs-mode: nil
498  * End:
499  * vim: shiftwidth=4 tabstop=8 expandtab
500  */
501