Member and_not in Z_Operator is kept for backwards compatibility.
[yaz-moved-to-github.git] / zutil / pquery.c
1 /*
2  * Copyright (c) 1995-1998, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: pquery.c,v $
7  * Revision 1.6  2001-03-07 13:24:40  adam
8  * Member and_not in Z_Operator is kept for backwards compatibility.
9  * Added support for definition of CCL operators in field spec file.
10  *
11  * Revision 1.5  2001/02/21 13:46:54  adam
12  * C++ fixes.
13  *
14  * Revision 1.4  1999/12/21 16:25:20  adam
15  * Fixed handling of default/inherited attributes.
16  *
17  * Revision 1.3  1999/12/20 15:20:13  adam
18  * Implemented ccl_pquery to convert from CCL tree to prefix query.
19  *
20  * Revision 1.2  1999/11/30 13:47:12  adam
21  * Improved installation. Moved header files to include/yaz.
22  *
23  * Revision 1.1  1999/06/08 10:10:16  adam
24  * New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
25  *
26  * Revision 1.22  1999/04/20 09:56:49  adam
27  * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
28  * Modified all encoders/decoders to reflect this change.
29  *
30  * Revision 1.21  1998/10/13 16:03:37  adam
31  * Better checking for invalid OID's in p_query_rpn.
32  *
33  * Revision 1.20  1998/03/31 15:13:20  adam
34  * Development towards compiled ASN.1.
35  *
36  * Revision 1.19  1998/03/05 08:09:03  adam
37  * Minor change to make C++ happy.
38  *
39  * Revision 1.18  1998/02/11 11:53:36  adam
40  * Changed code so that it compiles as C++.
41  *
42  * Revision 1.17  1997/11/24 11:33:57  adam
43  * Using function odr_nullval() instead of global ODR_NULLVAL when
44  * appropriate.
45  *
46  * Revision 1.16  1997/09/29 13:19:00  adam
47  * Added function, oid_ent_to_oid, to replace the function
48  * oid_getoidbyent, which is not thread safe.
49  *
50  * Revision 1.15  1997/09/29 07:13:43  adam
51  * Changed type of a few variables to avoid warnings.
52  *
53  * Revision 1.14  1997/09/22 12:33:41  adam
54  * Fixed bug introduced by previous commit.
55  *
56  * Revision 1.13  1997/09/17 12:10:42  adam
57  * YAZ version 1.4.
58  *
59  * Revision 1.12  1997/09/01 08:54:13  adam
60  * New windows NT/95 port using MSV5.0. Made prefix query handling
61  * thread safe. The function options ignores empty arguments when met.
62  *
63  * Revision 1.11  1996/11/11 13:15:29  adam
64  * Added proximity operator.
65  *
66  * Revision 1.10  1996/08/12 14:10:35  adam
67  * New function p_query_attset to define default attribute set.
68  *
69  * Revision 1.9  1996/03/15  11:03:46  adam
70  * Attribute set can be set globally for a query with the @attrset
71  * operator. The @attr operator has an optional attribute-set specifier
72  * that sets the attribute set locally.
73  *
74  * Revision 1.8  1996/01/02  11:46:56  quinn
75  * Changed 'operator' to 'roperator' to avoid C++ conflict.
76  *
77  * Revision 1.7  1995/09/29  17:12:36  quinn
78  * Smallish
79  *
80  * Revision 1.6  1995/09/27  15:03:03  quinn
81  * Modified function heads & prototypes.
82  *
83  * Revision 1.5  1995/06/15  12:31:02  quinn
84  * *** empty log message ***
85  *
86  * Revision 1.4  1995/06/15  07:45:19  quinn
87  * Moving to v3.
88  *
89  * Revision 1.3  1995/06/14  11:06:35  adam
90  * Bug fix: Attributes wasn't interpreted correctly!
91  *
92  * Revision 1.2  1995/05/26  08:56:11  adam
93  * New function: p_query_scan.
94  *
95  * Revision 1.1  1995/05/22  15:31:49  adam
96  * New function, p_query_rpn, to convert from prefix (ascii) to rpn (asn).
97  *
98  */
99
100 #include <stdio.h>
101 #include <string.h>
102 #include <stdlib.h>
103
104 #include <yaz/proto.h>
105 #include <yaz/oid.h>
106 #include <yaz/pquery.h>
107
108 static oid_value p_query_dfset = VAL_NONE;
109
110 struct lex_info {
111     const char *query_buf;
112     const char *lex_buf;
113     size_t lex_len;
114     int query_look;
115     char *left_sep;
116     char *right_sep;
117     int escape_char;
118     int term_type;
119 };
120
121 static Z_RPNStructure *rpn_structure (struct lex_info *li, ODR o, oid_proto, 
122                                       int num_attr, int max_attr, 
123                                       int *attr_list, oid_value *attr_set);
124
125 static enum oid_value query_oid_getvalbyname (struct lex_info *li)
126 {
127     enum oid_value value;
128     char buf[32];
129
130     if (li->lex_len > 31)
131         return VAL_NONE;
132     memcpy (buf, li->lex_buf, li->lex_len);
133     buf[li->lex_len] = '\0';
134     value = oid_getvalbyname (buf);
135     return value;
136 }
137
138 static int compare_term (struct lex_info *li, const char *src, size_t off)
139 {
140     size_t len=strlen(src);
141
142     if (li->lex_len == len+off && !memcmp (li->lex_buf+off, src, len-off))
143         return 1;
144     return 0;
145 }
146
147 static int query_token (struct lex_info *li)
148 {
149     const char *sep_match;
150     const char **qptr = &li->query_buf;
151
152     while (**qptr == ' ')
153         (*qptr)++;
154     if (**qptr == '\0')
155         return 0;
156     li->lex_len = 0;
157     if ((sep_match = strchr (li->left_sep, **qptr)))
158     {
159         int sep_index = sep_match - li->left_sep;
160         
161         ++(*qptr);
162         li->lex_buf = *qptr;
163         while (**qptr && **qptr != li->right_sep[sep_index])
164         {
165             ++(li->lex_len);
166             ++(*qptr);
167         }
168         if (**qptr)
169             ++(*qptr);
170     }
171     else
172     {
173         li->lex_buf = *qptr;
174         while (**qptr && **qptr != ' ')
175         {
176             ++(li->lex_len);
177             ++(*qptr);
178         }
179     }
180     if (li->lex_len >= 1 && li->lex_buf[0] == li->escape_char)
181     {
182         if (compare_term (li, "and", 1))
183             return 'a';
184         if (compare_term (li, "or", 1))
185             return 'o';
186         if (compare_term (li, "not", 1))
187             return 'n';
188         if (compare_term (li, "attr", 1))
189             return 'l';
190         if (compare_term (li, "set", 1))
191             return 's';
192         if (compare_term (li, "attrset", 1))
193             return 'r';
194         if (compare_term (li, "prox", 1))
195             return 'p';
196         if (compare_term (li, "term", 1))
197             return 'y';
198     }
199     return 't';
200 }
201
202 static int lex (struct lex_info *li)
203 {
204     return li->query_look = query_token (li);
205 }
206
207 static Z_AttributesPlusTerm *rpn_term (struct lex_info *li, ODR o,
208                                        oid_proto proto, 
209                                        int num_attr, int *attr_list,
210                                        oid_value *attr_set)
211 {
212     Z_AttributesPlusTerm *zapt;
213     Odr_oct *term_octet;
214     Z_Term *term;
215     Z_AttributeElement **elements;
216
217     zapt = (Z_AttributesPlusTerm *)odr_malloc (o, sizeof(*zapt));
218     term_octet = (Odr_oct *)odr_malloc (o, sizeof(*term_octet));
219     term = (Z_Term *)odr_malloc (o, sizeof(*term));
220
221     if (!num_attr)
222         elements = (Z_AttributeElement**)odr_nullval();
223     else
224     {
225         int i, k = 0;
226         int *attr_tmp;
227
228         elements = (Z_AttributeElement**)
229             odr_malloc (o, num_attr * sizeof(*elements));
230
231         attr_tmp = (int *)odr_malloc (o, num_attr * 2 * sizeof(int));
232         memcpy (attr_tmp, attr_list, num_attr * 2 * sizeof(int));
233         for (i = num_attr; --i >= 0; )
234         {
235             int j;
236             for (j = i+1; j<num_attr; j++)
237                 if (attr_tmp[2*j] == attr_tmp[2*i])
238                     break;
239             if (j < num_attr)
240                 continue;
241             elements[k] =
242                 (Z_AttributeElement*)odr_malloc (o,sizeof(**elements));
243             elements[k]->attributeType = &attr_tmp[2*i];
244             if (attr_set[i] == VAL_NONE)
245                 elements[k]->attributeSet = 0;
246             else
247             {
248                 oident attrid;
249                 int oid[OID_SIZE];
250                 
251                 attrid.proto = PROTO_Z3950;
252                 attrid.oclass = CLASS_ATTSET;
253                 attrid.value = attr_set[i];
254                    
255                 elements[k]->attributeSet =
256                     odr_oiddup (o, oid_ent_to_oid (&attrid, oid));
257             }
258             elements[k]->which = Z_AttributeValue_numeric;
259             elements[k]->value.numeric = &attr_tmp[2*i+1];
260             k++;
261         }
262         num_attr = k;
263     }
264 #ifdef ASN_COMPILED
265     zapt->attributes = (Z_AttributeList *)
266         odr_malloc (o, sizeof(*zapt->attributes));
267     zapt->attributes->num_attributes = num_attr;
268     zapt->attributes->attributes = elements;
269 #else
270     zapt->num_attributes = num_attr;
271     zapt->attributeList = elements;
272 #endif    
273
274     zapt->term = term;
275     term->which = Z_Term_general;
276     term->u.general = term_octet;
277     term_octet->buf = (unsigned char *)odr_malloc (o, li->lex_len);
278     term_octet->size = term_octet->len = li->lex_len;
279     memcpy (term_octet->buf, li->lex_buf, li->lex_len);
280     return zapt;
281 }
282
283 static Z_Operand *rpn_simple (struct lex_info *li, ODR o, oid_proto proto,
284                               int num_attr, int *attr_list,
285                               oid_value *attr_set)
286 {
287     Z_Operand *zo;
288
289     zo = (Z_Operand *)odr_malloc (o, sizeof(*zo));
290     switch (li->query_look)
291     {
292     case 't':
293         zo->which = Z_Operand_APT;
294         if (!(zo->u.attributesPlusTerm =
295               rpn_term (li, o, proto, num_attr, attr_list, attr_set)))
296             return NULL;
297         lex (li);
298         break;
299     case 's':
300         lex (li);
301         if (!li->query_look)
302             return NULL;
303         zo->which = Z_Operand_resultSetId;
304         zo->u.resultSetId = (char *)odr_malloc (o, li->lex_len+1);
305         memcpy (zo->u.resultSetId, li->lex_buf, li->lex_len);
306         zo->u.resultSetId[li->lex_len] = '\0';
307         lex (li);
308         break;
309     default:
310         return NULL;
311     }
312     return zo;
313 }
314
315 static Z_ProximityOperator *rpn_proximity (struct lex_info *li, ODR o)
316 {
317     Z_ProximityOperator *p = (Z_ProximityOperator *)odr_malloc (o, sizeof(*p));
318
319     if (!lex (li))
320         return NULL;
321     if (*li->lex_buf == '1')
322     {
323         p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
324         *p->exclusion = 1;
325     } 
326     else if (*li->lex_buf == '0')
327     {
328         p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
329         *p->exclusion = 0;
330     }
331     else
332         p->exclusion = NULL;
333
334     if (!lex (li))
335         return NULL;
336     p->distance = (int *)odr_malloc (o, sizeof(*p->distance));
337     *p->distance = atoi (li->lex_buf);
338
339     if (!lex (li))
340         return NULL;
341     p->ordered = (int *)odr_malloc (o, sizeof(*p->ordered));
342     *p->ordered = atoi (li->lex_buf);
343     
344     if (!lex (li))
345         return NULL;
346     p->relationType = (int *)odr_malloc (o, sizeof(*p->relationType));
347     *p->relationType = atoi (li->lex_buf);
348
349     if (!lex (li))
350         return NULL;
351     if (*li->lex_buf == 'k')
352         p->which = 0;
353     else if (*li->lex_buf == 'p')
354         p->which = 1;
355     else
356         p->which = atoi (li->lex_buf);
357
358     if (!lex (li))
359         return NULL;
360 #ifdef ASN_COMPILED
361     p->which = Z_ProximityOperator_known;
362     p->u.known = (int *)odr_malloc (o, sizeof(*p->u.known));
363     *p->u.known = atoi (li->lex_buf);
364 #else
365     p->proximityUnitCode = (int *)odr_malloc (o, sizeof(*p->proximityUnitCode));
366     *p->proximityUnitCode = atoi (li->lex_buf);
367 #endif
368     return p;
369 }
370
371 static Z_Complex *rpn_complex (struct lex_info *li, ODR o, oid_proto proto,
372                                int num_attr, int max_attr, 
373                                int *attr_list, oid_value *attr_set)
374 {
375     Z_Complex *zc;
376     Z_Operator *zo;
377
378     zc = (Z_Complex *)odr_malloc (o, sizeof(*zc));
379     zo = (Z_Operator *)odr_malloc (o, sizeof(*zo));
380     zc->roperator = zo;
381     switch (li->query_look)
382     {
383     case 'a':
384         zo->which = Z_Operator_and;
385         zo->u.and_not = odr_nullval();
386         break;
387     case 'o':
388         zo->which = Z_Operator_or;
389         zo->u.and_not = odr_nullval();
390         break;
391     case 'n':
392         zo->which = Z_Operator_and_not;
393         zo->u.and_not = odr_nullval();
394         break;
395     case 'p':
396         zo->which = Z_Operator_prox;
397         zo->u.prox = rpn_proximity (li, o);
398         if (!zo->u.prox)
399             return NULL;
400         break;
401     default:
402         return NULL;
403     }
404     lex (li);
405     if (!(zc->s1 =
406           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
407                          attr_set)))
408         return NULL;
409     if (!(zc->s2 =
410           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
411                          attr_set)))
412         return NULL;
413     return zc;
414 }
415
416 static Z_RPNStructure *rpn_structure (struct lex_info *li, ODR o,
417                                       oid_proto proto, 
418                                       int num_attr, int max_attr, 
419                                       int *attr_list, oid_value *attr_set)
420 {
421     Z_RPNStructure *sz;
422     const char *cp;
423
424     sz = (Z_RPNStructure *)odr_malloc (o, sizeof(*sz));
425     switch (li->query_look)
426     {
427     case 'a':
428     case 'o':
429     case 'n':
430     case 'p':
431         sz->which = Z_RPNStructure_complex;
432         if (!(sz->u.complex =
433               rpn_complex (li, o, proto, num_attr, max_attr, attr_list,
434                            attr_set)))
435             return NULL;
436         break;
437     case 't':
438     case 's':
439         sz->which = Z_RPNStructure_simple;
440         if (!(sz->u.simple =
441               rpn_simple (li, o, proto, num_attr, attr_list,
442                           attr_set)))
443             return NULL;
444         break;
445     case 'l':
446         lex (li);
447         if (!li->query_look)
448             return NULL;
449         if (num_attr >= max_attr)
450             return NULL;
451         if (!(cp = strchr (li->lex_buf, '=')) ||
452             (size_t) (cp-li->lex_buf) > li->lex_len)
453         {
454             attr_set[num_attr] = query_oid_getvalbyname (li);
455             if (attr_set[num_attr] == VAL_NONE)
456                 return NULL;
457             lex (li);
458
459             if (!(cp = strchr (li->lex_buf, '=')))
460                 return NULL;
461         }
462         else 
463         {
464             if (num_attr > 0)
465                 attr_set[num_attr] = attr_set[num_attr-1];
466             else
467                 attr_set[num_attr] = VAL_NONE;
468         }
469         attr_list[2*num_attr] = atoi(li->lex_buf); 
470         attr_list[2*num_attr+1] = atoi (cp+1);
471         num_attr++;
472         lex (li);
473         return
474             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
475                            attr_set);
476     case 'y':
477         lex (li);
478         if (!li->query_look)
479             return NULL;
480         if (compare_term (li, "general", 0))
481             li->term_type = Z_Term_general;
482         else if (compare_term (li, "numeric", 0))
483             li->term_type = Z_Term_numeric;
484         else if (compare_term (li, "string", 0))
485             li->term_type = Z_Term_characterString;
486         else if (compare_term (li, "oid", 0))
487             li->term_type = Z_Term_oid;
488         else if (compare_term (li, "datetime", 0))
489             li->term_type = Z_Term_dateTime;
490         else if (compare_term (li, "null", 0))
491             li->term_type = Z_Term_null;
492         lex (li);
493         return
494             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
495                            attr_set);
496     case 0:                /* operator/operand expected! */
497         return NULL;
498     }
499     return sz;
500 }
501
502 Z_RPNQuery *p_query_rpn_mk (ODR o, struct lex_info *li, oid_proto proto,
503                             const char *qbuf)
504 {
505     Z_RPNQuery *zq;
506     int attr_array[1024];
507     oid_value attr_set[512];
508     oid_value topSet = VAL_NONE;
509     oident oset;
510     int oid[OID_SIZE];
511
512     zq = (Z_RPNQuery *)odr_malloc (o, sizeof(*zq));
513     lex (li);
514     if (li->query_look == 'r')
515     {
516         lex (li);
517         topSet = query_oid_getvalbyname (li);
518         if (topSet == VAL_NONE)
519             return NULL;
520
521         lex (li);
522     }
523     if (topSet == VAL_NONE)
524         topSet = p_query_dfset;
525     if (topSet == VAL_NONE)
526         topSet = VAL_BIB1;
527     oset.proto = proto;
528     oset.oclass = CLASS_ATTSET;
529     oset.value = topSet;
530
531     if (!oid_ent_to_oid (&oset, oid))
532         return NULL;
533     zq->attributeSetId = odr_oiddup (o, oid);
534
535     if (!(zq->RPNStructure = rpn_structure (li, o, proto, 0, 512,
536                                             attr_array, attr_set)))
537         return NULL;
538     return zq;
539 }
540
541 Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto,
542                          const char *qbuf)
543 {
544     struct lex_info li;
545     
546     li.left_sep = "{\"";
547     li.right_sep = "}\"";
548     li.escape_char = '@';
549     li.term_type = Z_Term_general;
550     li.query_buf = qbuf;
551     return p_query_rpn_mk (o, &li, proto, qbuf);
552 }
553
554 Z_AttributesPlusTerm *p_query_scan_mk (struct lex_info *li,
555                                        ODR o, oid_proto proto,
556                                        Odr_oid **attributeSetP,
557                                        const char *qbuf)
558 {
559     int attr_list[1024];
560     oid_value attr_set[512];
561     int num_attr = 0;
562     int max_attr = 512;
563     const char *cp;
564     oid_value topSet = VAL_NONE;
565     oident oset;
566     int oid[OID_SIZE];
567
568     lex (li);
569     if (li->query_look == 'r')
570     {
571         lex (li);
572         topSet = query_oid_getvalbyname (li);
573
574         lex (li);
575     }
576     if (topSet == VAL_NONE)
577         topSet = p_query_dfset;
578     if (topSet == VAL_NONE)
579         topSet = VAL_BIB1;
580     oset.proto = proto;
581     oset.oclass = CLASS_ATTSET;
582     oset.value = topSet;
583
584     *attributeSetP = odr_oiddup (o, oid_ent_to_oid (&oset, oid));
585
586     while (li->query_look == 'l')
587     {
588         lex (li);
589         if (!li->query_look)
590             return NULL;
591         if (num_attr >= max_attr)
592             return NULL;
593
594         if (!(cp = strchr (li->lex_buf, '=')) ||
595             (size_t) (cp-li->lex_buf) > li->lex_len)
596         {
597             attr_set[num_attr] = query_oid_getvalbyname (li);
598             lex (li);
599
600             if (!(cp = strchr (li->lex_buf, '=')))
601                 return NULL;
602         }
603         else
604         {
605             if (num_attr > 0)
606                 attr_set[num_attr] = attr_set[num_attr-1];
607             else
608                 attr_set[num_attr] = VAL_NONE;
609         }
610         attr_list[2*num_attr] = atoi (li->lex_buf);
611         attr_list[2*num_attr+1] = atoi (cp+1);
612         num_attr++;
613         lex (li);
614     }
615     if (!li->query_look)
616         return NULL;
617     return rpn_term (li, o, proto, num_attr, attr_list, attr_set);
618 }
619
620 Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
621                                     Odr_oid **attributeSetP,
622                                     const char *qbuf)
623 {
624     struct lex_info li;
625
626     li.left_sep = "{\"";
627     li.right_sep = "}\"";
628     li.escape_char = '@';
629     li.term_type = Z_Term_general;
630     li.query_buf = qbuf;
631
632     return p_query_scan_mk (&li, o, proto, attributeSetP, qbuf);
633 }
634
635 int p_query_attset (const char *arg)
636 {
637     p_query_dfset = oid_getvalbyname (arg);
638     return (p_query_dfset == VAL_NONE) ? -1 : 0;
639 }
640