(file) Return to wql.c CVS log (file) (dir) Up to [OMI] / omi / wql

  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           }

ViewCVS 0.9.2