DRY the schema lookup
[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
155     YAZ_CHECK(test_uri(s, "http://x/y", "full",
156                        "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
157                        "PREFIX bf: <http://bibframe.org/vocab/>\n"
158                        "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
159                        "SELECT ?sub ?rel WHERE ?work = <http://x/y>\n"));
160
161     YAZ_CHECK(test_query(
162                   s, "@attr 1=bf.title computer",
163                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
164                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
165                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
166                   "SELECT ?title ?author ?description ?ititle\n"
167                   "WHERE {\n"
168                   "  ?work a bf:Work .\n"
169                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
170                   "  ?work bf:creator/bf:label ?author .\n"
171                   "  ?work bf:note ?description .\n"
172                   "  ?inst bf:instanceOf ?work .\n"
173                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
174                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
175                   "  ?work bf:workTitle/bf:titleValue ?o1 "
176                   "FILTER(contains(?o1, \"computer\"))\n"
177                   "}\n"
178                   ));
179
180     YAZ_CHECK(test_query(
181                   s, "@attr 1=bf.creator london",
182                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
183                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
184                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
185                   "SELECT ?title ?author ?description ?ititle\n"
186                   "WHERE {\n"
187                   "  ?work a bf:Work .\n"
188                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
189                   "  ?work bf:creator/bf:label ?author .\n"
190                   "  ?work bf:note ?description .\n"
191                   "  ?inst bf:instanceOf ?work .\n"
192                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
193                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
194                   "  ?work bf:creator/bf:label ?o2 "
195                   "FILTER(contains(?o2, \"london\"))\n"
196                   "}\n"));
197
198
199     YAZ_CHECK(test_query(
200                   s, "@and @attr 1=bf.creator london @attr 1=bf.title computer",
201                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
202                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
203                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
204                   "SELECT ?title ?author ?description ?ititle\n"
205                   "WHERE {\n"
206                   "  ?work a bf:Work .\n"
207                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
208                   "  ?work bf:creator/bf:label ?author .\n"
209                   "  ?work bf:note ?description .\n"
210                   "  ?inst bf:instanceOf ?work .\n"
211                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
212                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
213                   "  ?work bf:creator/bf:label ?o2 "
214                   "FILTER(contains(?o2, \"london\")) .\n"
215                   "  ?work bf:workTitle/bf:titleValue ?o1 "
216                   "FILTER(contains(?o1, \"computer\"))\n"
217                   "}\n"));
218
219     YAZ_CHECK(test_query(
220                   s, "@or @attr 1=bf.creator london @attr 1=bf.title computer",
221                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
222                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
223                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
224                   "SELECT ?title ?author ?description ?ititle\n"
225                   "WHERE {\n"
226                   "  ?work a bf:Work .\n"
227                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
228                   "  ?work bf:creator/bf:label ?author .\n"
229                   "  ?work bf:note ?description .\n"
230                   "  ?inst bf:instanceOf ?work .\n"
231                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
232                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
233                   "  {\n"
234                   "   ?work bf:creator/bf:label ?o2 "
235                   "FILTER(contains(?o2, \"london\"))\n"
236                   "  } UNION {\n"
237                   "   ?work bf:workTitle/bf:titleValue ?o1 "
238                   "FILTER(contains(?o1, \"computer\"))\n"
239                   "  }\n"
240                   "}\n"
241                   ));
242
243     YAZ_CHECK(test_query(
244                   s, "@or @or @attr 1=bf.creator a @attr 1=bf.title b @attr 1=bf.title c",
245                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
246                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
247                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
248                   "SELECT ?title ?author ?description ?ititle\n"
249                   "WHERE {\n"
250                   "  ?work a bf:Work .\n"
251                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
252                   "  ?work bf:creator/bf:label ?author .\n"
253                   "  ?work bf:note ?description .\n"
254                   "  ?inst bf:instanceOf ?work .\n"
255                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
256                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
257                   "  {\n"
258                   "   {\n"
259                   "    ?work bf:creator/bf:label ?o2 "
260                   "FILTER(contains(?o2, \"a\"))\n"
261                   "   } UNION {\n"
262                   "    ?work bf:workTitle/bf:titleValue ?o1 "
263                   "FILTER(contains(?o1, \"b\"))\n"
264                   "   }\n"
265                   "  } UNION {\n"
266                   "   ?work bf:workTitle/bf:titleValue ?o1 "
267                   "FILTER(contains(?o1, \"c\"))\n"
268                   "  }\n"
269                   "}\n"
270                   ));
271
272     YAZ_CHECK(test_query(
273                   s, "@or @and @attr 1=bf.creator a @attr 1=bf.title b @attr 1=bf.title c",
274                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
275                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
276                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
277                   "SELECT ?title ?author ?description ?ititle\n"
278                   "WHERE {\n"
279                   "  ?work a bf:Work .\n"
280                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
281                   "  ?work bf:creator/bf:label ?author .\n"
282                   "  ?work bf:note ?description .\n"
283                   "  ?inst bf:instanceOf ?work .\n"
284                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
285                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
286                   "  {\n"
287                   "   ?work bf:creator/bf:label ?o2 "
288                   "FILTER(contains(?o2, \"a\")) .\n"
289                   "   ?work bf:workTitle/bf:titleValue ?o1 "
290                   "FILTER(contains(?o1, \"b\"))\n"
291                   "  } UNION {\n"
292                   "   ?work bf:workTitle/bf:titleValue ?o1 "
293                   "FILTER(contains(?o1, \"c\"))\n"
294                   "  }\n"
295                   "}\n"
296                   ));
297
298     YAZ_CHECK(test_query(
299                   s, "@and @and @attr 1=bf.creator a @attr 1=bf.title b @attr 1=bf.title c",
300                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
301                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
302                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
303                   "SELECT ?title ?author ?description ?ititle\n"
304                   "WHERE {\n"
305                   "  ?work a bf:Work .\n"
306                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
307                   "  ?work bf:creator/bf:label ?author .\n"
308                   "  ?work bf:note ?description .\n"
309                   "  ?inst bf:instanceOf ?work .\n"
310                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
311                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
312                   "  ?work bf:creator/bf:label ?o2 "
313                   "FILTER(contains(?o2, \"a\")) .\n"
314                   "  ?work bf:workTitle/bf:titleValue ?o1 "
315                   "FILTER(contains(?o1, \"b\")) .\n"
316                   "  ?work bf:workTitle/bf:titleValue ?o1 "
317                   "FILTER(contains(?o1, \"c\"))\n"
318                   "}\n"
319                   ));
320
321     YAZ_CHECK(test_query(
322                   s, "@and @attr 1=bf.title \"Phantom Tollbooth\" "
323                   "@attr 1=bf.nearby \"40.1583 83.0742 30\"",
324                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
325                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
326                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
327                   "SELECT ?title ?author ?description ?ititle\n"
328                   "WHERE {\n"
329                   "  ?work a bf:Work .\n"
330                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
331                   "  ?work bf:creator/bf:label ?author .\n"
332                   "  ?work bf:note ?description .\n"
333                   "  ?inst bf:instanceOf ?work .\n"
334                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
335                   "  ?inst bf:heldBy ?lib .\n"
336                   "  ?work bf:workTitle/bf:titleValue ?o1 "
337                   "FILTER(contains(?o1, \"Phantom Tollbooth\")) .\n"
338                   "  ?lib gs:nearby (40.1583 83.0742 30)\n"
339                   "}\n"
340                   ));
341
342     YAZ_CHECK(test_query(
343                   s, "@attr 1=bf.isbn 9780316154697",
344                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
345                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
346                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
347                   "SELECT ?title ?author ?description ?ititle\n"
348                   "WHERE {\n"
349                   "  ?work a bf:Work .\n"
350                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
351                   "  ?work bf:creator/bf:label ?author .\n"
352                   "  ?work bf:note ?description .\n"
353                   "  ?inst bf:instanceOf ?work .\n"
354                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
355                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
356                   "  ?inst bf:ISBN \"9780316154697\"\n"
357                   "}\n"
358                  ));
359
360
361     yaz_sparql_destroy(s);
362 }
363
364 static void tst2(void)
365 {
366     yaz_sparql_t s = yaz_sparql_create();
367
368     yaz_sparql_add_pattern(s, "prefix",
369                            "rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns");
370     yaz_sparql_add_pattern(s, "prefix",
371                            "bf: <http://bibframe.org/vocab/>");
372     yaz_sparql_add_pattern(s, "prefix",
373                            "gs: http://gs.com/panorama/domain-model");
374     yaz_sparql_add_pattern(s, "form", "SELECT ?title ?author ?description ?ititle");
375     yaz_sparql_add_pattern(s, "criteria", "?work a bf:Work");
376     yaz_sparql_add_pattern(s, "criteria", "?work bf:workTitle/bf:titleValue ?title");
377     yaz_sparql_add_pattern(s, "criteria", "?work bf:creator/bf:label ?author");
378     yaz_sparql_add_pattern(s, "criteria", "?work bf:note ?description");
379     yaz_sparql_add_pattern(s, "criteria", "?inst bf:instanceOf ?work");
380     yaz_sparql_add_pattern(s, "criteria", "?inst bf:instanceTitle/bf:titleValue ?ititle");
381     yaz_sparql_add_pattern(s, "criteria.optional", "?inst bf:heldBy ?lib");
382
383     yaz_sparql_add_pattern(s, "index.bf.title",
384                            "?work bf:workTitle/bf:titleValue %v "
385                            "FILTER(contains(%v, %s))");
386     yaz_sparql_add_pattern(s, "index.bf.creator",
387                            "?work bf:creator/bf:label %v "
388                            "FILTER(contains(%v, %s))");
389     yaz_sparql_add_pattern(s, "index.bf.authorityCreator",
390                            "?work bf:author %s");
391     yaz_sparql_add_pattern(s, "index.bf.type", "?inst rdf:type %s");
392     yaz_sparql_add_pattern(s, "index.bf.format",
393                            "?inst bf:format %v FILTER(contains(%v, %s))");
394     yaz_sparql_add_pattern(s, "index.bf.nearby", "?lib gs:nearby (%d)");
395     yaz_sparql_add_pattern(s, "index.bf.baseTitle",
396                            "?work bf:derivativeOf/bf:workTitle/bf:titleValue "
397                            "%v FILTER(contains(%v, %s))");
398     yaz_sparql_add_pattern(s, "index.bf.baseCreator",
399                            "?work bf:derivativeOf/bf:creator/bf:label "
400                            "%v FILTER(contains(%v, %s))");
401     yaz_sparql_add_pattern(s, "index.bf.targetAudience",
402                            "?work bf:targetAudience %s");
403     yaz_sparql_add_pattern(s, "index.bf.isbn", "?inst bf:ISBN %s");
404
405     YAZ_CHECK(test_query(
406                   s, "@attr 1=bf.title computer",
407                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
408                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
409                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
410                   "SELECT ?title ?author ?description ?ititle\n"
411                   "WHERE {\n"
412                   "  ?work a bf:Work .\n"
413                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
414                   "  ?work bf:creator/bf:label ?author .\n"
415                   "  ?work bf:note ?description .\n"
416                   "  ?inst bf:instanceOf ?work .\n"
417                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
418                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
419                   "  ?work bf:workTitle/bf:titleValue ?v0 "
420                   "FILTER(contains(?v0, \"computer\"))\n"
421                   "}\n"
422                   ));
423
424     YAZ_CHECK(test_query(
425                   s, "@attr 1=bf.creator london",
426                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
427                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
428                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
429                   "SELECT ?title ?author ?description ?ititle\n"
430                   "WHERE {\n"
431                   "  ?work a bf:Work .\n"
432                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
433                   "  ?work bf:creator/bf:label ?author .\n"
434                   "  ?work bf:note ?description .\n"
435                   "  ?inst bf:instanceOf ?work .\n"
436                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
437                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
438                   "  ?work bf:creator/bf:label ?v0 "
439                   "FILTER(contains(?v0, \"london\"))\n"
440                   "}\n"));
441
442     YAZ_CHECK(test_query(
443                   s, "@or @and @attr 1=bf.creator a @attr 1=bf.title b @attr 1=bf.title c",
444                   "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
445                   "PREFIX bf: <http://bibframe.org/vocab/>\n"
446                   "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
447                   "SELECT ?title ?author ?description ?ititle\n"
448                   "WHERE {\n"
449                   "  ?work a bf:Work .\n"
450                   "  ?work bf:workTitle/bf:titleValue ?title .\n"
451                   "  ?work bf:creator/bf:label ?author .\n"
452                   "  ?work bf:note ?description .\n"
453                   "  ?inst bf:instanceOf ?work .\n"
454                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
455                   "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
456                   "  {\n"
457                   "   ?work bf:creator/bf:label ?v0 "
458                   "FILTER(contains(?v0, \"a\")) .\n"
459                   "   ?work bf:workTitle/bf:titleValue ?v1 "
460                   "FILTER(contains(?v1, \"b\"))\n"
461                   "  } UNION {\n"
462                   "   ?work bf:workTitle/bf:titleValue ?v2 "
463                   "FILTER(contains(?v2, \"c\"))\n"
464                   "  }\n"
465                   "}\n"
466                   ));
467
468     yaz_sparql_destroy(s);
469 }
470
471 int main(int argc, char **argv)
472 {
473     YAZ_CHECK_INIT(argc, argv);
474     YAZ_CHECK_LOG();
475     tst1();
476     tst2();
477     YAZ_CHECK_TERM;
478 }
479 /*
480  * Local variables:
481  * c-basic-offset: 4
482  * c-file-style: "Stroustrup"
483  * indent-tabs-mode: nil
484  * End:
485  * vim: shiftwidth=4 tabstop=8 expandtab
486  */
487