OW_WQLSelectStatement.cpp

Go to the documentation of this file.
00001 //%/////////////////////////////////////////////////////////////////////////////
00002 //
00003 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
00004 // The Open Group, Tivoli Systems
00005 // Portions Copyright (C) 2003-2004 Vintela, Inc. All rights reserved.
00006 //
00007 // Permission is hereby granted, free of charge, to any person obtaining a copy
00008 // of this software and associated documentation files (the "Software"), to
00009 // deal in the Software without restriction, including without limitation the
00010 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00011 // sell copies of the Software, and to permit persons to whom the Software is
00012 // furnished to do so, subject to the following conditions:
00013 // 
00014 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
00015 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
00016 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
00017 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
00018 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00019 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00020 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00021 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 //
00023 //==============================================================================
00024 //
00025 // Author: Mike Brasher (mbrasher@bmc.com)
00026 //
00027 // Modified By: Dan Nuffer
00028 //
00029 //%/////////////////////////////////////////////////////////////////////////////
00030 #include "OW_config.h"
00031 #include "OW_StringBuffer.hpp"
00032 #include "OW_WQLSelectStatement.hpp"
00033 #include "OW_Stack.hpp"
00034 #include "OW_WQLCompile.hpp"
00035 #include "OW_Assertion.hpp"
00036 
00037 #if defined(OW_HAVE_OSTREAM)
00038 #include <ostream>
00039 #else
00040 #include <iostream>
00041 #endif
00042 
00043 namespace OW_NAMESPACE
00044 {
00045 
00046 // TODO: Merge this code with WQLCompile.cpp, it's all duplicated.
00047 //     Worse, it's an ODR violation, for which no diagnostic is
00048 //     required, and which has undefined behavoir.
00049 template<class T>
00050 inline static bool _Compare(const T& x, const T& y, WQLOperation op)
00051 {
00052    switch (op)
00053    {
00054       case WQL_EQ: 
00055          return x == y;
00056       case WQL_NE: 
00057          return x != y;
00058       case WQL_LT: 
00059          return x < y;
00060       case WQL_LE: 
00061          return x <= y;
00062       case WQL_GT: 
00063          return x > y;
00064       case WQL_GE: 
00065          return x >= y;
00066       default:
00067          OW_ASSERT(0);
00068    }
00069    return false;
00070 }
00071 static bool _Evaluate(
00072       const WQLOperand& lhs, 
00073       const WQLOperand& rhs, 
00074       WQLOperation op)
00075 {
00076    switch (lhs.getType())
00077    {
00078       case WQLOperand::NULL_VALUE:
00079          {
00080             // return true if the op is WQL_EQ and the rhs is NULL
00081             // also if op is WQL_NE and rhs is not NULL
00082             return !(op == WQL_EQ) ^ (rhs.getType() == WQLOperand::NULL_VALUE);
00083             break;
00084          }
00085       case WQLOperand::INTEGER_VALUE:
00086          {
00087             return _Compare(
00088                   lhs.getIntegerValue(),
00089                   rhs.getIntegerValue(),
00090                   op);
00091          }
00092       case WQLOperand::DOUBLE_VALUE:
00093          {
00094             return _Compare(
00095                   lhs.getDoubleValue(),
00096                   rhs.getDoubleValue(),
00097                   op);
00098          }
00099       case WQLOperand::BOOLEAN_VALUE:
00100          {
00101             return _Compare(
00102                   lhs.getBooleanValue(),
00103                   rhs.getBooleanValue(),
00104                   op);
00105          }
00106       case WQLOperand::STRING_VALUE:
00107          {
00108             return _Compare(
00109                   lhs.getStringValue(),
00110                   rhs.getStringValue(),
00111                   op);
00112          }
00113       default:
00114          OW_ASSERT(0);
00115    }
00116    return false;
00117 }
00118 WQLSelectStatement::WQLSelectStatement()
00119 {
00120    _operStack.reserve(32);
00121 }
00122 WQLSelectStatement::~WQLSelectStatement()
00123 {
00124 }
00125 void WQLSelectStatement::clear()
00126 {
00127    _className.erase();
00128    _selectPropertyNames.clear();
00129    _operStack.clear();
00130 }
00131 bool WQLSelectStatement::appendWherePropertyName(const String& x)
00132 {
00133    //
00134    // Reject duplicate property names by returning false.
00135    //
00136    for (size_t i = 0, n = _wherePropertyNames.size(); i < n; i++)
00137    {
00138       if (_wherePropertyNames[i] == x)
00139       {
00140          return false;
00141       }
00142    }
00143    //
00144    // Append the new property.
00145    //
00146    _wherePropertyNames.append(x);
00147    return true;
00148 }
00149 static inline void _ResolveProperty(
00150       WQLOperand& op,
00151       const WQLPropertySource* source)
00152 {
00153    //
00154    // Resolve the operand: if it's a property name, look up its value:
00155    //
00156    if (op.getType() == WQLOperand::PROPERTY_NAME)
00157    {
00158       const String& propertyName = op.getPropertyName();
00159       // it's up to the source to handle embedded properties.
00160       if (!source->getValue(propertyName, op))
00161       {
00162          OW_THROW(NoSuchPropertyException, propertyName.c_str());
00163       }
00164    }
00165 }
00166 bool WQLSelectStatement::evaluateWhereClause(
00167       const WQLPropertySource* source) const
00168 {
00169    if (!hasWhereClause())
00170    {
00171       return true;
00172    }
00173    Stack<WQLOperand> stack;
00174    //
00175    // Process each of the operations:
00176    //
00177    for (UInt32 i = 0, n = _operStack.size(); i < n; i++)
00178    {
00179       const WQLSelectStatement::OperandOrOperation& curItem = _operStack[i];
00180       if (curItem.m_type == WQLSelectStatement::OperandOrOperation::OPERAND)
00181       {
00182          // put it onto the stack
00183          stack.push(curItem.m_operand);
00184       }
00185       else
00186       {
00187          WQLOperation op = curItem.m_operation;
00188          switch (op)
00189          {
00190             case WQL_OR:
00191                {
00192                   OW_ASSERT(stack.size() >= 2);
00193                   WQLOperand op1 = stack.top();
00194                   stack.pop();
00195                   WQLOperand& op2 = stack.top();
00196                   bool b1 = op1.getBooleanValue();
00197                   bool b2 = op2.getBooleanValue();
00198                   stack.top() = WQLOperand(b1 || b2, WQL_BOOLEAN_VALUE_TAG);
00199                   break;
00200                }
00201             case WQL_AND:
00202                {
00203                   OW_ASSERT(stack.size() >= 2);
00204                   WQLOperand op1 = stack.top();
00205                   stack.pop();
00206                   WQLOperand& op2 = stack.top();
00207                   bool b1 = op1.getBooleanValue();
00208                   bool b2 = op2.getBooleanValue();
00209                   stack.top() = WQLOperand(b1 && b2, WQL_BOOLEAN_VALUE_TAG);
00210                   break;
00211                }
00212             case WQL_NOT:
00213                {
00214                   OW_ASSERT(stack.size() >= 1);
00215                   WQLOperand& op = stack.top();
00216                   bool b1 = op.getBooleanValue();
00217                   stack.top() = WQLOperand(!b1, WQL_BOOLEAN_VALUE_TAG);
00218                   break;
00219                }
00220             case WQL_EQ:
00221             case WQL_NE:
00222             case WQL_LT:
00223             case WQL_LE:
00224             case WQL_GT:
00225             case WQL_GE:
00226                {
00227                   OW_ASSERT(stack.size() >= 2);
00228                   //
00229                   // Resolve the left-hand-side to a value (if not already
00230                   // a value).
00231                   //
00232                   WQLOperand lhs = stack.top();
00233                   stack.pop();
00234                   _ResolveProperty(lhs, source);
00235                   //
00236                   // Resolve the right-hand-side to a value (if not already
00237                   // a value).
00238                   //
00239                   WQLOperand& rhs = stack.top();
00240                   _ResolveProperty(rhs, source);
00241                   //
00242                   // Check for a type mismatch:
00243                   //
00244                   if (rhs.getType() != lhs.getType())
00245                   {
00246                      OW_THROW(TypeMismatchException, "");
00247                   }
00248                   //
00249                   // Now that the types are known to be alike, apply the
00250                   // operation:
00251                   //
00252                   stack.top() = WQLOperand(_Evaluate(lhs, rhs, op), WQL_BOOLEAN_VALUE_TAG);
00253                   break;
00254                }
00255             case WQL_ISA:
00256                {
00257                   OW_ASSERT(stack.size() >= 2);
00258                   WQLOperand lhs = stack.top();
00259                   stack.pop();
00260                   if (lhs.getType() != WQLOperand::PROPERTY_NAME)
00261                   {
00262                      OW_THROW(TypeMismatchException, "First argument of ISA must be a property name");
00263                   }
00264                   WQLOperand& rhs = stack.top();
00265                   String className;
00266                   if (rhs.getType() == WQLOperand::PROPERTY_NAME)
00267                   {
00268                      className = rhs.getPropertyName();
00269                   }
00270                   else if (rhs.getType() == WQLOperand::STRING_VALUE)
00271                   {
00272                      className = rhs.getStringValue();
00273                   }
00274                   else
00275                   {
00276                      OW_THROW(TypeMismatchException, "Second argument of ISA must be a property name or string constant");
00277                   }
00278                   stack.top() = WQLOperand(source->evaluateISA(lhs.getPropertyName(), className), WQL_BOOLEAN_VALUE_TAG);
00279                   break;
00280                   break;
00281                }
00282             case WQL_DO_NOTHING:
00283                {
00284                   OW_ASSERT(0); // should never happen
00285                   break;
00286                }
00287          }
00288       }
00289    }
00290    OW_ASSERT(stack.size() == 1);
00291    return stack.top().getBooleanValue();
00292 }
00293 void WQLSelectStatement::print(std::ostream& ostr) const
00294 {
00295    ostr << "WQLSelectStatement\n";
00296    ostr << "{\n";
00297    ostr << "   _className: \"" << _className << "\"\n";
00298    for (size_t i = 0; i < _selectPropertyNames.size(); i++)
00299    {
00300       if (i == 0)
00301       {
00302          ostr << '\n';
00303       }
00304       ostr << "   _selectPropertyNames[" << i << "]: ";
00305       ostr << '"' << _selectPropertyNames[i] << '"' << '\n';
00306    }
00307    // Print the operations/operands
00308    for (size_t i = 0; i < _operStack.size(); i++)
00309    {
00310       if (i == 0)
00311       {
00312          ostr << '\n';
00313       }
00314       ostr << "   _operStack[" << i << "]: ";
00315       ostr << '"' << _operStack[i].toString() << '"' << '\n';
00316    }
00317    ostr << "}" << std::endl;
00318 }
00319 String WQLSelectStatement::toString() const
00320 {
00321    StringBuffer buf("select ");
00322    if (_selectPropertyNames.size())
00323    {
00324       for (size_t i = 0; i < _selectPropertyNames.size(); i++)
00325       {
00326          if (i != 0)
00327          {
00328             buf += ", ";
00329          }
00330          buf += _selectPropertyNames[i];
00331       }
00332    }
00333    else
00334    {
00335       // can this happen?
00336       buf += " *";
00337    }
00338    buf += " from ";
00339    buf += _className;
00340    // Print the operations/operands
00341    for (size_t i = 0; i < _operStack.size(); i++)
00342    {
00343       if (i == 0)
00344       {
00345          buf += "\n";
00346       }
00347       buf += " _operStack[" + String(UInt32(i)) + "]: ";
00348       buf += "\"" + _operStack[i].toString() + "\"\n";
00349    }
00350    buf += ")";
00351    return buf.toString();
00352 }
00353 void WQLSelectStatement::compileWhereClause(
00354       const WQLPropertySource* /*source*/, WQLCompile& wcl)
00355 {
00356    wcl.compile(this);
00357 }
00358 
00359 } // end namespace OW_NAMESPACE
00360 

Generated on Thu Feb 9 08:48:18 2006 for openwbem by  doxygen 1.4.6