1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include "wql.h"
26
27 #ifndef _MSC_VER
28 #include <pthread.h>
29 #endif
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <base/strings.h>
35 #include <base/classdecl.h>
36 #include <base/helpers.h>
37 #include <base/io.h>
38 #include "wqlyacc.h"
39 #include "state.h"
40
41 extern int wqlparse();
42
43 mike 1.1 WQL_State wqlstate;
44
45 #ifndef _MSC_VER
46 static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
47 static void _Lock() { pthread_mutex_lock(&_mutex); }
48 static void _Unlock() { pthread_mutex_unlock(&_mutex); }
49 #endif
50
51 void* wqlmalloc(size_t size)
52 {
53 return Batch_Get(wqlstate.wql->batch, size);
54 }
55
56 MI_Char* wqlstrdup(const MI_Char * str)
57 {
58 return Batch_Zdup(wqlstate.wql->batch, str);
59 }
60
61 WQL* WQL_Parse(const MI_Char* text, Batch* batch)
62 {
63 WQL* self = NULL;
64 mike 1.1 int deleteBatch;
65
66 /* Acquire mutex to synchronize access to global Lex/Yacc state */
67 _Lock();
68
69 /* Create batch if none */
70 if (!batch)
71 {
72 batch = Batch_New(64);
73
74 if (!batch)
75 {
76 _Unlock();
77 return NULL;
78 }
79
80 deleteBatch = 1;
81 }
82 else
83 {
84 deleteBatch = 0;
85 mike 1.1 }
86
87 /* Allocate the WQL object */
88 {
89 self = (WQL*)Batch_GetClear(batch, sizeof(WQL));
90
91 if (!self)
92 {
93 if (deleteBatch)
94 Batch_Delete(batch);
95
96 _Unlock();
97 return NULL;
98 }
99 }
100
101 /* Initialize WQL object */
102 self->batch = batch;
103 self->deleteBatch = deleteBatch;
104 self->text = Batch_Zdup(batch, text);
105
106 mike 1.1 /* Initialize global parser state */
107 memset(&wqlstate, 0, sizeof(WQL_State));
108 wqlstate.text = self->text;
109 wqlstate.size = (int)Zlen(text);
110 wqlstate.wql = self;
111 wqlstate.ptr = text;
112
113 /* Parse the text */
114 wqlparse();
115
116 /* Get return status */
117 if (wqlstate.status != 0)
118 {
119 WQL_Delete(self);
120 self = NULL;
121 }
122
123 /* Clear global parser state */
124 memset(&wqlstate, 0, sizeof(WQL_State));
125
126 _Unlock();
127 mike 1.1 return self;
128 }
129
130 WQL* WQL_Clone(const WQL* self, Batch* batch)
131 {
132 WQL* result;
133 int deleteBatch;
134 size_t i;
135
136 /* Check for null parameter */
137 if (!self)
138 return NULL;
139
140 /* Create batch if none */
141 if (!batch)
142 {
143 batch = Batch_New(64);
144
145 if (!batch)
146 return NULL;
147
148 mike 1.1 deleteBatch = 1;
149 }
150 else
151 deleteBatch = 0;
152
153 /* Allocate the WQL object */
154 {
155 result = (WQL*)Batch_GetClear(batch, sizeof(WQL));
156
157 if (!result)
158 goto failed;
159 }
160
161 /* Initialize batch fields */
162 result->batch = batch;
163 result->deleteBatch = deleteBatch;
164
165 /* Clone properties */
166 {
167 for (i = 0; i < self->nproperties; i++)
168 {
169 mike 1.1 result->properties[i] = Batch_Zdup(batch, self->properties[i]);
170
171 if (!result->properties[i])
172 goto failed;
173 }
174
175 result->nproperties = self->nproperties;
176 }
177
178 /* Clone classname */
179 if (self->className)
180 {
181 result->className = Batch_Zdup(batch, self->className);
182
183 if (!result->className)
184 goto failed;
185 }
186
187 /* Clone symbols */
188 {
189 for (i = 0; i < self->nsymbols; i++)
190 mike 1.1 {
191 result->symbols[i] = self->symbols[i];
192
193 if (self->symbols[i].type == WQL_TYPE_IDENTIFIER ||
194 self->symbols[i].type == WQL_TYPE_STRING)
195 {
196 if (self->symbols[i].value.string)
197 {
198 result->symbols[i].value.string =
199 Batch_Zdup(batch, self->symbols[i].value.string);
200
201 if (!result->symbols[i].value.string)
202 goto failed;
203 }
204 }
205 }
206
207 result->nsymbols = self->nsymbols;
208 }
209
210 /* Clone text */
211 mike 1.1 if (self->text)
212 {
213 result->text = Batch_Zdup(batch, self->text);
214
215 if (!result->text)
216 goto failed;
217 }
218
219 return result;
220
221 failed:
222
223 if (deleteBatch)
224 Batch_Delete(batch);
225
226 return NULL;
227 }
228
229 void WQL_Delete(WQL* self)
230 {
231 if (self->deleteBatch)
232 mike 1.1 Batch_Delete(self->batch);
233 }
234
235 /* YACC calls this function to report errors */
236 void wqlerror(const char * msg)
237 {
238 MI_UNUSED(msg);
239 wqlstate.status = -1;
240 }
241
242 MI_Boolean WQL_ContainsProperty(
243 const WQL* wql,
244 const MI_Char* propertyName)
245 {
246 size_t i;
247
248 if (wql->nproperties == 0)
249 return MI_TRUE;
250
251 for (i = 0; i < wql->nproperties; i++)
252 {
253 mike 1.1 if (Zcasecmp(propertyName, wql->properties[i]) == 0)
254 return MI_TRUE;
255 }
256
257 /* Not found! */
258 return MI_FALSE;
259 }
260
261 int _ValidateLookup(
262 const MI_Char* name,
263 WQL_Symbol* symbol,
264 Batch* batch,
265 void* data)
266 {
267 const MI_ClassDecl* cd = (const MI_ClassDecl*)data;
268 const MI_PropertyDecl* pd;
269
270 MI_UNUSED(batch);
271
272 /* Check for null parameters */
273 if (!name || !symbol || !data)
274 mike 1.1 return -1;
275
276 /* Lookup the property with this name */
277 {
278 pd = ClassDecl_FindPropertyDecl(cd, name);
279
280 if (!pd)
281 return -1;
282 }
283
284 /* Convert to symbol */
285 switch (pd->type)
286 {
287 case MI_BOOLEAN:
288 symbol->type = WQL_TYPE_BOOLEAN;
289 symbol->value.boolean = 0;
290 return 0;
291 case MI_UINT8:
292 case MI_SINT8:
293 case MI_UINT16:
294 case MI_SINT16:
295 mike 1.1 case MI_UINT32:
296 case MI_SINT32:
297 case MI_UINT64:
298 case MI_SINT64:
299 case MI_CHAR16:
300 symbol->type = WQL_TYPE_INTEGER;
301 symbol->value.integer = 0;
302 return 0;
303 case MI_REAL32:
304 case MI_REAL64:
305 symbol->type = WQL_TYPE_REAL;
306 symbol->value.real = 0.0;
307 return 0;
308 case MI_DATETIME:
309 case MI_STRING:
310 symbol->type = WQL_TYPE_STRING;
311 symbol->value.string = MI_T("");
312 return 0;
313 default:
314 break;
315 }
316 mike 1.1
317 /* Unknown token type */
318 return -1;
319 }
320
321 int WQL_Validate(const WQL* self, const MI_ClassDecl* cd)
322 {
323 size_t i;
324
325 /* Verify that properties in SELECT list exist in class declaration */
326 for (i = 0; i < self->nproperties; i++)
327 {
328 if (!ClassDecl_FindPropertyDecl(cd, self->properties[i]))
329 return -1;
330 }
331
332 /* Perform mock evaluation to find non-existent properties and
333 * property-literal mismatches.
334 */
335 if (WQL_Eval(self, _ValidateLookup, (void*)cd) == -1)
336 return -1;
337 mike 1.1
338 return 0;
339 }
340
341 static int _Compare(const WQL_Symbol* s1, const WQL_Symbol* s2)
342 {
343 switch (s1->type)
344 {
345 case WQL_TYPE_BOOLEAN:
346 {
347 return s1->value.boolean - s2->value.boolean;
348 }
349 case WQL_TYPE_INTEGER:
350 {
351 if (s1->value.integer < s2->value.integer)
352 return -1;
353 else if (s1->value.integer > s2->value.integer)
354 return 1;
355 else
356 return 0;
357 }
358 mike 1.1 case WQL_TYPE_REAL:
359 {
360 if (s1->value.real < s2->value.real)
361 return -1;
362 else if (s1->value.real > s2->value.real)
363 return 1;
364 else
365 return 0;
366 }
367 case WQL_TYPE_STRING:
368 {
369 return Zcmp(s1->value.string, s2->value.string);
370 }
371 default:
372 return -1;
373 }
374 }
375
376 extern int WQL_Eval(
377 const WQL* wql,
378 WQL_Lookup lookup,
379 mike 1.1 void* data)
380 {
381 size_t i;
382 WQL_Symbol symbols[WQL_MAX_SYMBOLS];
383 size_t nsymbols = 0;
384
385 if (!wql || !wql->className || !lookup)
386 return -1;
387
388 /* Return success if there is no WHERE clause */
389 if (wql->nsymbols == 0)
390 return 0;
391
392 /* Perform postfix evaluation */
393 for (i = 0; i < wql->nsymbols; i++)
394 {
395 const WQL_Symbol* sym = &wql->symbols[i];
396 WQL_Type type = sym->type;
397
398 switch (type)
399 {
400 mike 1.1 case WQL_TYPE_AND:
401 case WQL_TYPE_OR:
402 {
403 if (nsymbols < 2)
404 return -1;
405
406 {
407 WQL_Symbol s2 = symbols[--nsymbols];
408 WQL_Symbol s1 = symbols[--nsymbols];
409 WQL_Symbol s;
410 int f;
411
412 if (s1.type != WQL_TYPE_BOOLEAN)
413 return -1;
414 if (s2.type != WQL_TYPE_BOOLEAN)
415 return -1;
416
417 s.type = WQL_TYPE_BOOLEAN;
418
419 if (type == WQL_TYPE_OR)
420 f = (s1.value.boolean || s2.value.boolean);
421 mike 1.1 else
422 f = (s1.value.boolean && s2.value.boolean);
423
424 s.value.boolean = f ? 1 : 0;
425 symbols[nsymbols++] = s;
426 }
427
428 break;
429 }
430 case WQL_TYPE_NOT:
431 {
432 if (nsymbols < 1)
433 return -1;
434
435 {
436 WQL_Symbol s1 = symbols[--nsymbols];
437 WQL_Symbol s;
438
439 if (s1.type != WQL_TYPE_BOOLEAN)
440 return -1;
441
442 mike 1.1 s.type = WQL_TYPE_BOOLEAN;
443 s.value.boolean = (!s1.value.boolean) ? 1 : 0;
444 symbols[nsymbols++] = s;
445 }
446
447 break;
448 }
449 case WQL_TYPE_EQ:
450 case WQL_TYPE_NE:
451 case WQL_TYPE_LT:
452 case WQL_TYPE_LE:
453 case WQL_TYPE_GT:
454 case WQL_TYPE_GE:
455 {
456 if (nsymbols < 2)
457 return -1;
458
459 {
460 WQL_Symbol s2 = symbols[--nsymbols];
461 WQL_Symbol s1 = symbols[--nsymbols];
462 WQL_Symbol s;
463 mike 1.1 int r;
464 int f;
465
466 /* If either operand is null */
467 if (s1.type == WQL_TYPE_NULL || s2.type == WQL_TYPE_NULL)
468 {
469 /* Set flag non-zero if both operands are null */
470 int bothNull =
471 (s1.type==WQL_TYPE_NULL && s2.type==WQL_TYPE_NULL);
472
473 if (type == WQL_TYPE_EQ)
474 {
475 s.type = WQL_TYPE_BOOLEAN;
476 s.value.boolean = bothNull ? 1 : 0;
477 symbols[nsymbols++] = s;
478 break;
479 }
480 else if (type == WQL_TYPE_NE)
481 {
482 s.type = WQL_TYPE_BOOLEAN;
483 s.value.boolean = bothNull ? 0 : 1;
484 mike 1.1 symbols[nsymbols++] = s;
485 break;
486 }
487 else
488 return -1;
489 }
490 else
491 {
492 /* Reject type mismatch */
493 if (s1.type != s2.type)
494 return -1;
495
496 r = _Compare(&s1, &s2);
497
498 switch (type)
499 {
500 case WQL_TYPE_EQ:
501 f = (r == 0);
502 break;
503 case WQL_TYPE_NE:
504 f = (r != 0);
505 mike 1.1 break;
506 case WQL_TYPE_LT:
507 f = (r < 0);
508 break;
509 case WQL_TYPE_LE:
510 f = (r <= 0);
511 break;
512 case WQL_TYPE_GT:
513 f = (r > 0);
514 break;
515 case WQL_TYPE_GE:
516 f = (r >= 0);
517 break;
518 default:
519 f = 0;
520 break;
521 }
522
523 s.type = WQL_TYPE_BOOLEAN;
524 s.value.boolean = f ? 1 : 0;
525 symbols[nsymbols++] = s;
526 mike 1.1 }
527 }
528 break;
529 }
530 case WQL_TYPE_IDENTIFIER:
531 {
532 WQL_Symbol tmp;
533
534 memset(&tmp, 0, sizeof(WQL_Symbol));
535
536 if ((*lookup)(sym->value.string, &tmp, wql->batch, data) != 0)
537 return -1;
538
539 if (tmp.type != WQL_TYPE_BOOLEAN &&
540 tmp.type != WQL_TYPE_INTEGER &&
541 tmp.type != WQL_TYPE_REAL &&
542 tmp.type != WQL_TYPE_STRING &&
543 tmp.type != WQL_TYPE_NULL)
544 {
545 return -1;
546 }
547 mike 1.1
548 symbols[nsymbols++] = tmp;
549 break;
550 }
551 case WQL_TYPE_BOOLEAN:
552 case WQL_TYPE_INTEGER:
553 case WQL_TYPE_REAL:
554 case WQL_TYPE_STRING:
555 case WQL_TYPE_NULL:
556 symbols[nsymbols++] = *sym;
557 break;
558 }
559 }
560
561 /* There should be exactly 1 symbol left on stack */
562 if (nsymbols != 1)
563 return -1;
564
565 /* Final token on stack should be boolean */
566 if (symbols[0].type != WQL_TYPE_BOOLEAN)
567 return -1;
568 mike 1.1
569 /* Return '0' for equal, '1' for not-equal */
570 if (symbols[0].value.boolean)
571 return 0;
572 else
573 return 1;
574 }
575
576 int WQL_LookupInstanceProperty(
577 const MI_Char* name,
578 WQL_Symbol* symbol,
579 Batch* batch,
580 void* data)
581 {
582 const MI_Instance* instance = (const MI_Instance*)data;
583 MI_Result r;
584 MI_Value value;
585 MI_Type type;
586 MI_Uint32 flags;
587
588 /* Check for null parameters */
589 mike 1.1 if (!name || !symbol || !data)
590 return -1;
591
592 /* Lookup the property with this name */
593 r = __MI_Instance_GetElement(instance, name, &value, &type, &flags, 0);
594
595 /* Fail if not found */
596 if (r != MI_RESULT_OK)
597 return -1;
598
599 /* Handle null case */
600 if (flags & MI_FLAG_NULL)
601 {
602 symbol->type = WQL_TYPE_NULL;
603 return 0;
604 }
605
606 /* Convert to symbol */
607 switch (type)
608 {
609 case MI_BOOLEAN:
610 mike 1.1 {
611 symbol->type = WQL_TYPE_BOOLEAN;
612 symbol->value.boolean = value.boolean;
613 return 0;
614 }
615 case MI_UINT8:
616 {
617 symbol->type = WQL_TYPE_INTEGER;
618 symbol->value.integer = (MI_Sint64)value.uint8;
619 return 0;
620 }
621 case MI_SINT8:
622 {
623 symbol->type = WQL_TYPE_INTEGER;
624 symbol->value.integer = (MI_Sint64)value.sint8;
625 return 0;
626 }
627 case MI_UINT16:
628 case MI_CHAR16:
629 {
630 symbol->type = WQL_TYPE_INTEGER;
631 mike 1.1 symbol->value.integer = (MI_Sint64)value.uint16;
632 return 0;
633 }
634 case MI_SINT16:
635 {
636 symbol->type = WQL_TYPE_INTEGER;
637 symbol->value.integer = (MI_Sint64)value.sint16;
638 return 0;
639 }
640 case MI_UINT32:
641 {
642 symbol->type = WQL_TYPE_INTEGER;
643 symbol->value.integer = (MI_Sint64)value.uint32;
644 return 0;
645 }
646 case MI_SINT32:
647 {
648 symbol->type = WQL_TYPE_INTEGER;
649 symbol->value.integer = (MI_Sint64)value.sint32;
650 return 0;
651 }
652 mike 1.1 case MI_UINT64:
653 {
654 /* ATTN: note that MAX(MI_Uint64) cannot be represented */
655 symbol->type = WQL_TYPE_INTEGER;
656 symbol->value.integer = (MI_Sint64)value.uint64;
657 return 0;
658 }
659 case MI_SINT64:
660 {
661 symbol->type = WQL_TYPE_INTEGER;
662 symbol->value.integer = (MI_Sint64)value.sint64;
663 return 0;
664 }
665 case MI_REAL32:
666 {
667 symbol->type = WQL_TYPE_REAL;
668 symbol->value.real = (MI_Real32)value.real32;
669 return 0;
670 }
671 case MI_REAL64:
672 {
673 mike 1.1 symbol->type = WQL_TYPE_REAL;
674 symbol->value.real = value.real64;
675 return 0;
676 }
677 case MI_DATETIME:
678 {
679 MI_Char buf[26];
680 DatetimeToStr(&value.datetime, buf);
681 symbol->type = WQL_TYPE_STRING;
682 symbol->value.string = Batch_Zdup(batch, buf);
683 return 0;
684 }
685 case MI_STRING:
686 {
687 symbol->type = WQL_TYPE_STRING;
688 symbol->value.string = Batch_Zdup(batch, value.string);
689 return 0;
690 }
691
692 /* These types are not permitted in WQL WHERE clauses */
693 case MI_REFERENCE:
694 mike 1.1 case MI_INSTANCE:
695 case MI_BOOLEANA:
696 case MI_UINT8A:
697 case MI_SINT8A:
698 case MI_UINT16A:
699 case MI_SINT16A:
700 case MI_UINT32A:
701 case MI_SINT32A:
702 case MI_UINT64A:
703 case MI_SINT64A:
704 case MI_REAL32A:
705 case MI_REAL64A:
706 case MI_CHAR16A:
707 case MI_DATETIMEA:
708 case MI_STRINGA:
709 case MI_REFERENCEA:
710 case MI_INSTANCEA:
711 return -1;
712 }
713
714 /* Not found */
715 mike 1.1 return -1;
716 }
|