(file) Return to CQLSelectStatementRep.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / CQL

   1 karl  1.15 //%2006////////////////////////////////////////////////////////////////////////
   2 chuck 1.2  //
   3 karl  1.9  // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
   4            // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
   5            // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
   6 chuck 1.2  // IBM Corp.; EMC Corporation, The Open Group.
   7 karl  1.9  // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
   8            // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
   9            // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
  10            // EMC Corporation; VERITAS Software Corporation; The Open Group.
  11 karl  1.15 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
  12            // EMC Corporation; Symantec Corporation; The Open Group.
  13 chuck 1.2  //
  14            // Permission is hereby granted, free of charge, to any person obtaining a copy
  15            // of this software and associated documentation files (the "Software"), to
  16            // deal in the Software without restriction, including without limitation the
  17            // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  18            // sell copies of the Software, and to permit persons to whom the Software is
  19            // furnished to do so, subject to the following conditions:
  20 karl  1.15 // 
  21 chuck 1.2  // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
  22            // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
  23            // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
  24            // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  25            // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  26            // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  27            // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28            // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29            //
  30            //==============================================================================
  31            //
  32            //%/////////////////////////////////////////////////////////////////////////////
  33            
  34            #include "CQLSelectStatement.h"
  35            #include "CQLSelectStatementRep.h"
  36            
  37            #include <Pegasus/Common/CIMValue.h>
  38            #include <Pegasus/Common/CIMInstance.h>
  39            #include <Pegasus/Common/CIMProperty.h>
  40            #include <Pegasus/Query/QueryCommon/QueryException.h>
  41            #include <Pegasus/Query/QueryCommon/QueryIdentifier.h>
  42 chuck 1.2  #include <Pegasus/Query/QueryCommon/QueryChainedIdentifier.h>
  43 chuck 1.3  #include <Pegasus/Common/Tracer.h>
  44 chuck 1.2  #include <Pegasus/Common/InternalException.h>
  45            #include <Pegasus/Common/CIMStatusCode.h>
  46            #include <Pegasus/Common/AutoPtr.h>
  47            #include "CQLValue.h"
  48            #include "CQLIdentifier.h"
  49            #include "CQLChainedIdentifier.h"
  50            #include "Cql2Dnf.h"
  51            
  52 david.dillard 1.11 // ATTN: TODOs -
  53 chuck         1.2  // optimize
  54                    // documentation
  55                    
  56                    PEGASUS_NAMESPACE_BEGIN
  57                    
  58                    struct PropertyNode
  59                    {
  60 karl          1.18     CIMName name;              // property name
  61                        CIMName scope;             // class the property is on
  62                        Boolean wildcard;          // true if this property is wildcarded
  63                        Boolean endpoint;          // true if this property is an endpoint
  64 chuck         1.3                               // of a chained identifier
  65 karl          1.18     AutoPtr<PropertyNode> sibling;
  66                        AutoPtr<PropertyNode> firstChild;
  67                        
  68                        PropertyNode()
  69                            : wildcard(false),
  70                                endpoint(false),
  71                                sibling(NULL),
  72                                firstChild(NULL)
  73                        {}
  74                        
  75                        ~PropertyNode() {}
  76 chuck         1.2  };
  77                    
  78                    
  79                    CQLSelectStatementRep::CQLSelectStatementRep()
  80 karl          1.18     :SelectStatementRep(),
  81                        _hasWhereClause(false),
  82                        _contextApplied(false)
  83 chuck         1.2  {
  84 karl          1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep()");
  85                        PEG_METHOD_EXIT();
  86 chuck         1.2  }
  87                    
  88 kumpf         1.22 CQLSelectStatementRep::CQLSelectStatementRep(
  89                        const String& inQlang,
  90                        const String& inQuery,
  91                        const QueryContext& inCtx)
  92 karl          1.18     :SelectStatementRep(inQlang, inQuery, inCtx),
  93                        _hasWhereClause(false),
  94                        _contextApplied(false)
  95 chuck         1.2  {
  96 karl          1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep(inQlang,inQuery,inCtx)");
  97                        PEG_METHOD_EXIT();
  98 chuck         1.2  }
  99                    
 100 kumpf         1.22 CQLSelectStatementRep::CQLSelectStatementRep(
 101                        const String& inQlang,
 102                        const String& inQuery)
 103 karl          1.18     :SelectStatementRep(inQlang, inQuery),
 104                        _hasWhereClause(false),
 105                        _contextApplied(false)
 106 chuck         1.2  {
 107 karl          1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep(inQlang,inQuery)");
 108                        PEG_METHOD_EXIT();
 109 chuck         1.2  }
 110                    
 111                    CQLSelectStatementRep::CQLSelectStatementRep(const CQLSelectStatementRep& rep)
 112 karl          1.18     :SelectStatementRep(rep),
 113                        _selectIdentifiers(rep._selectIdentifiers),
 114                        _hasWhereClause(rep._hasWhereClause),
 115                        _predicate(rep._predicate),
 116                        _contextApplied(rep._contextApplied)
 117 chuck         1.2  {
 118 karl          1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep(rep)");
 119                        PEG_METHOD_EXIT();
 120 chuck         1.2  }
 121                    
 122                    CQLSelectStatementRep::~CQLSelectStatementRep()
 123                    {
 124 karl          1.18     PEG_METHOD_ENTER (TRC_CQL, "~CQLSelectStatementRep()");
 125                        PEG_METHOD_EXIT();
 126 chuck         1.2  }
 127                    
 128 karl          1.18 CQLSelectStatementRep& CQLSelectStatementRep::operator=(
 129                            const CQLSelectStatementRep& rhs)
 130 chuck         1.2  {
 131 karl          1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::operator=");
 132                        
 133                        if (this ==  &rhs)
 134                        {
 135                            PEG_METHOD_EXIT();
 136                            return *this;
 137                        }
 138                        
 139                        SelectStatementRep::operator=(rhs);
 140                        
 141                        _selectIdentifiers = rhs._selectIdentifiers;
 142                        _predicate = rhs._predicate;
 143                        _contextApplied = rhs._contextApplied;
 144                        _hasWhereClause = rhs._hasWhereClause;
 145                        
 146 chuck         1.3      PEG_METHOD_EXIT();
 147 chuck         1.2      return *this;
 148                    }
 149                    
 150 chuck         1.3  Boolean CQLSelectStatementRep::evaluate(const CIMInstance& inCI)
 151 chuck         1.2  {
 152 karl          1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::evaluate");
 153                        
 154                        if(_ctx == NULL)
 155                        {
 156                            PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"QC not set");
 157                            PEG_METHOD_EXIT();
 158                            MessageLoaderParms parms(
 159                                "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
 160                                "Trying to process a query with a NULL Query Context.");
 161                            throw CQLRuntimeException(parms);
 162                        }
 163                        
 164                        // Apply to class contexts to the identifiers.
 165                        // This will check for a well-formed statement.
 166                        if (!_contextApplied)
 167                            applyContext();
 168                        
 169                        // Make sure the type of instance passed in is the FROM class,
 170                        // or a subclass of the FROM class.
 171                        if (!isFromChild(inCI.getClassName()))
 172                        {
 173 karl          1.18         PEG_METHOD_EXIT();
 174                            return false;
 175                        }
 176                        
 177                        if (!hasWhereClause())
 178 chuck         1.2      {
 179 karl          1.18         PEG_METHOD_EXIT();
 180                            return true;
 181 chuck         1.2      }
 182 dave.sudlik   1.20 
 183                        PEG_METHOD_EXIT();
 184                        return _predicate.evaluate(inCI, *_ctx);
 185 chuck         1.2  }
 186                    
 187 kumpf         1.21 void CQLSelectStatementRep::applyProjection(
 188                        CIMInstance& inCI,
 189 david.dillard 1.13     Boolean allowMissing)
 190 chuck         1.2  {
 191 karl          1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::applyProjection(inCI)");
 192                        
 193                        if(_ctx == NULL)
 194                        {
 195                            PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"QC not set");
 196                            PEG_METHOD_EXIT();
 197                            MessageLoaderParms parms(
 198                                "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
 199                                "Trying to process a query with a NULL Query Context.");
 200                            throw CQLRuntimeException(parms);
 201                        }
 202                        
 203                        // Apply to class contexts to the identifiers.
 204                        // This will check for a well-formed statement.
 205                        if (!_contextApplied)
 206 kumpf         1.21         applyContext();
 207 chuck         1.2  
 208 karl          1.18     //
 209                        // Build a tree to represent the projected properties from the select list
 210                        // of chained identifiers.  This is needed because embedded instances below
 211                        // the FROM class form a tree structure when projected.
 212                        //
 213                        // The design of the tree is to gather all the required properties for
 214                        // an instance at a node as child nodes.  The root node
 215                        // of the tree represents the instance passed in to this function.  
 216                        // Below the
 217                        // root there can be nodes that are required embedded instance properties.
 218                        // The child nodes of these embedded instance nodes represent the required
 219                        // properties on the embedded instance (which may themselves be embedded 
 220                        // instances).
 221                        //
 222                        // Each node has a name, which is in 2 parts -- the property name and the
 223                        // scope (ie. the class the property is on).  This allows the scoping
 224                        // operator to be handled correctly, so that the parent instance can be
 225                        // checked to see if it is the right class to provide the property.
 226                        // Note that the scoping is a base class; ie. the parent instance of a node
 227                        // may be a subclass of the scope.
 228                        //
 229 karl          1.18     
 230                        // Set up the root node of the tree.  This represents the instance
 231                        // passed in.
 232                        AutoPtr<PropertyNode> rootNode(new PropertyNode);
 233                        Array<QueryIdentifier> fromList = _ctx->getFromList();
 234                        rootNode->name = fromList[0].getName();  // not doing joins
 235                        rootNode->scope = fromList[0].getName(); // not used on root, just var fill
 236                        rootNode->wildcard = false;
 237                        
 238                        // Build the tree below the root.
 239                        for (Uint32 i = 0; i < _selectIdentifiers.size(); i++)
 240                        {
 241                            PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"select chained id = " +
 242                                              _selectIdentifiers[i].toString());
 243                            
 244                            // Get the chain elements
 245                            Array<CQLIdentifier> ids = _selectIdentifiers[i].getSubIdentifiers();
 246                            
 247                            PEGASUS_ASSERT(ids.size() > 1);
 248                            
 249                            PropertyNode * curNode = rootNode.get();
 250 karl          1.18         PropertyNode * curChild = curNode->firstChild.get();
 251                            
 252                            // Loop through the identifiers in the chain.
 253                            // NOTE: this starts at the position *after* the FROM class
 254                            // So, the loop index is always one position after the current node,
 255                            // ie. it will become a child node of the current node.
 256                            for (Uint32 j = 1; j < ids.size(); j++)
 257                            {
 258                                PEG_TRACE_STRING (TRC_CQL, 
 259                                      Tracer::LEVEL4,"curNode = " + curNode->name.getString());
 260                                PEG_TRACE_STRING (TRC_CQL,
 261                                      Tracer::LEVEL4,"id = " + ids[j].toString());
 262                                
 263                                // If the child is wildcarded, then every property exposed by the
 264                                // class of the instance at the current node is required.
 265                                // Mark the current node as wildcarded.
 266                                if (ids[j].isWildcard())
 267                                {
 268                                    PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"id is wildcard");
 269                                    curNode->wildcard = true;
 270                                    break;
 271 karl          1.18             }
 272                    
 273                                // Determine if this identifier is already a child node of
 274                                // the current node.
 275                                Boolean found = false;
 276                                while (curChild != NULL && !found)
 277                                {
 278                                    // The scoping class is either the scope of the identifier
 279                                    // or the FROM class if the identifier is not scoped.
 280                                    String scope = fromList[0].getName().getString();
 281                                    if (ids[j].isScoped())
 282                                    {
 283                                      scope = ids[j].getScope();
 284                                    }
 285                        
 286                                    PEG_TRACE_STRING (TRC_CQL, 
 287                                            Tracer::LEVEL4,"scope to compare = " + scope);
 288                            
 289                                    if (curChild->name == ids[j].getName() &&
 290                                        String::equalNoCase(curChild->scope.getString(), scope))
 291                                    {
 292 karl          1.18                     // Name and scope match.  The identifier is already 
 293                                        // child node.
 294                                        PEG_TRACE_CSTRING (TRC_CQL, 
 295                                              Tracer::LEVEL4,"id is already a child node");
 296                                        found = true;
 297                                    }
 298                                    else
 299                                    {
 300                                        curChild = curChild->sibling.get();
 301                                    }
 302                                }
 303                    
 304                                if (!found)
 305                                {
 306                                    // The identifier is not already a child node.
 307                                    // Create a node and add it as a child to the current node.
 308                                    PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"new child" +
 309                                                      ids[j].getName().getString());
 310                                    curChild = new PropertyNode;
 311                                    curChild->sibling.reset(curNode->firstChild.release());
 312                                    curChild->name = ids[j].getName();
 313 karl          1.18                 curChild->wildcard = false;
 314                                    curChild->endpoint = false;
 315                                    // the following is safer than using th = operator
 316                                    curNode->firstChild.reset(curChild);
 317                                }
 318                    
 319                                // Set the scope for the child node
 320                                if (ids[j].isScoped())
 321                                {
 322                                    // Child node has a scoping class
 323                                    PEGASUS_ASSERT(ids[j].getScope().size() > 0);
 324                                    PEG_TRACE_STRING (TRC_CQL, 
 325                                            Tracer::LEVEL4,"child set with scoping class: " +
 326                                            ids[j].getScope());
 327                                    curChild->scope =  CIMName(ids[j].getScope());
 328                                }
 329                                else
 330                                {
 331                                    // Not scoped.  The scope is the FROM class.
 332                                    PEGASUS_ASSERT(j == 1);
 333                                    PEGASUS_ASSERT(fromList[0].getName().getString().size() > 0);
 334 karl          1.18                 PEG_TRACE_STRING (TRC_CQL, 
 335                                            Tracer::LEVEL4,"child set with scoping class: " +
 336                                            fromList[0].getName().getString());
 337                                    curChild->scope = fromList[0].getName();
 338                                }
 339                        
 340                                // If the identifier is the last element of the chain,
 341                                // then mark it as an endpoint
 342                                if ((ids.size() - 1) == j)
 343                                {
 344                                    curChild->endpoint = true;
 345                                }
 346                        
 347                                curNode = curChild;
 348                                curChild = curNode->firstChild.get();
 349 chuck         1.2          }
 350 karl          1.18     }
 351                        
 352                        //
 353                        // Do the projection.
 354                        //
 355                    
 356                        Array<CIMName> requiredProps;
 357                        Boolean allPropsRequired = rootNode->wildcard;
 358                        
 359                        // Loop through the children of the root node.
 360                        // The root node represents the FROM class,
 361                        // and the child nodes are the required properties on the FROM class.
 362                        PropertyNode* childNode = rootNode->firstChild.get();
 363                        while (childNode != NULL)
 364                        {
 365                            PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,
 366                                "project childNode = " + childNode->name.getString());
 367                            
 368                            // Determine if the instance passed in meets the class scoping
 369                            // rules for the current child node.
 370                            Boolean filterable = isFilterable(inCI, childNode);
 371 karl          1.18         
 372                            // Indicates if the child node is still required after the 
 373                            // recursive call.
 374                            Boolean childRequired = true;
 375                            
 376                            // If the instance is filterable, and the child node has children,
 377                            // or is wildcarded, then the child is assumed to be an 
 378                            // embedded instance, and we need to recurse to apply the projection 
 379                            // on the embedded instance.
 380                            // (the check for embedded instance is done in the recursive call)
 381                            if (filterable &&
 382                                (childNode->firstChild.get() != NULL || childNode->wildcard))
 383 chuck         1.2          {
 384 karl          1.18             // We need to project on an embedded instance property. 
 385                                // The steps are to remove the embedded instance property from 
 386                                // the instance passed in, project on that embedded instance 
 387                                // property, and then add the projected
 388                                // embedded instance property back to the instance passed in.
 389                                PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,
 390                                    "about to recurse: " + childNode->name.getString());
 391                                Uint32 index = inCI.findProperty(childNode->name);
 392                                if (index != PEG_NOT_FOUND)
 393                                {
 394                                    // The instance passed in has the required embedded instance 
 395                                    // property.
 396                                    // Note: embedded instance property missing is caught below.
 397                                    
 398                                    // Remove the embedded instance property
 399                                    CIMProperty childProp = inCI.getProperty(index);
 400                                    inCI.removeProperty(index);
 401                                    
 402                                    // Project onto the embedded instance property.
 403                                    // If the last parameter is true, then the childNode
 404                                    // will not remove properties when filtering the 
 405 karl          1.18                 // embedded instance.
 406                                    // This call returns whether the embedded instance property
 407                                    // should be added to the required property list.
 408                                    childRequired = applyProjection(childNode, childProp, 
 409                                                                    allPropsRequired,
 410                                                                    allowMissing);
 411                                    inCI.addProperty(childProp);
 412                                }
 413 chuck         1.2          }
 414                    
 415 karl          1.18         // If the instance passed in is filterable,
 416                            // then add the current child to the list if it is still required.
 417                            if (filterable && childRequired)
 418                            {
 419                              PEG_TRACE_STRING (TRC_CQL,
 420                                  Tracer::LEVEL4,"add req prop: " + childNode->name.getString());
 421                              requiredProps.append(childNode->name);
 422                            }
 423 chuck         1.2  
 424                        childNode = childNode->sibling.get();
 425 karl          1.18     }
 426 chuck         1.2  
 427 karl          1.18     // Remove the properties that are not in the projection.
 428                        // This also checks for missing required properties.
 429                        Boolean preserve = false;
 430                        filterInstance(inCI,
 431 chuck         1.3                   allPropsRequired,
 432                                     fromList[0].getName(),
 433                                     requiredProps,
 434 carolann.graves 1.12                  preserve,
 435                                       allowMissing);
 436 chuck           1.2  }
 437                      
 438 kumpf           1.21 Boolean CQLSelectStatementRep::applyProjection(
 439                          PropertyNode* node,
 440                          CIMProperty& nodeProp,
 441                          Boolean& preservePropsForParent,
 442                          Boolean allowMissing) const
 443 chuck           1.2  {
 444 karl            1.18     PEG_METHOD_ENTER (TRC_CQL,
 445                            "CQLSelectStatementRep::applyProjection(node, nodeProp)");
 446                          
 447                          PEGASUS_ASSERT(node->firstChild.get() != NULL || node->wildcard);
 448                          
 449                          //
 450                          // The property passed in must be an embedded instance. It is not
 451                          // allowed to project properties on embedded classes.
 452                          // Get the embedded instance from the property.
 453                          //
 454                          
 455                          // First check that it is an embedded object
 456                          CIMValue nodeVal = nodeProp.getValue();
 457                          CIMType nodeValType = nodeVal.getType();
 458                          if (nodeValType != CIMTYPE_OBJECT
 459 a.dunfey        1.16 #ifdef PEGASUS_EMBEDDED_INSTANCE_SUPPORT
 460                          && nodeValType != CIMTYPE_INSTANCE
 461                      #endif // PEGASUS_EMBEDDED_INSTANCE_SUPPORT
 462 karl            1.18         )
 463                          {
 464                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"not emb");
 465                              PEG_METHOD_EXIT();
 466                              MessageLoaderParms parms(
 467                                  "CQL.CQLSelectStatementRep.PROP_NOT_EMB",
 468                                  "The property $0 must contain an embedded object.",
 469                                  nodeProp.getName().getString());
 470                              throw CQLRuntimeException(parms);
 471                          }
 472 chuck           1.2  
 473 karl            1.18     if (nodeVal.isNull())
 474                          {
 475                              // Since we will be projecting on the embedded object, it
 476                              //  cannot be null
 477                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"value is null");
 478                              PEG_METHOD_EXIT();
 479                              MessageLoaderParms parms(
 480                                  "CQL.CQLSelectStatementRep.NULL_EMB_OBJ",
 481                                  "The embedded object property $0 cannot contain a null value.",
 482                                  nodeProp.getName().getString());
 483                              throw CQLRuntimeException(parms);
 484                          }
 485                      
 486                          if (nodeVal.isArray() &&
 487 chuck           1.2        (node->firstChild.get() != NULL || node->wildcard))
 488 karl            1.18     {
 489                              // NOTE - since we are blocking projection of array elements, we can
 490                              // assume that if we get here we were told to project a whole array 
 491                              // (ie. no index used), as
 492                              // an embedded object with properties or wildcard.
 493                              // Examples not allowed:  
 494                              //   SELECT fromClass.someArrayProp.scope::notAllowedProp FROM fromClass
 495                              //   SELECT fromClass.someArrayProp.* FROM fromClass
 496                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"array index needed");
 497                              PEG_METHOD_EXIT();
 498                              MessageLoaderParms parms("CQL.CQLSelectStatementRep.PROJ_WHOLE_ARRAY",
 499                                            "CQL requires that array indexing is used on embedded"
 500                                                  " object property $0.",
 501                                             nodeProp.getName().getString());
 502                              throw CQLRuntimeException(parms);
 503                          }
 504 chuck           1.3  
 505 karl            1.18     CIMObject nodeObj;  // this starts uninitialized
 506                          CIMInstance nodeInst;
 507 a.dunfey        1.16 #ifdef PEGASUS_EMBEDDED_INSTANCE_SUPPORT
 508 karl            1.18     if(nodeValType == CIMTYPE_OBJECT)
 509                          {
 510 a.dunfey        1.16 #endif // PEGASUS_EMBEDDED_INSTANCE_SUPPORT
 511 karl            1.18     nodeVal.get(nodeObj);
 512                          if (nodeObj.isUninitialized())
 513                          {
 514                              // Not allowed to project on an uninitialized object
 515                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"is uninitialized");
 516                              PEG_METHOD_EXIT();
 517                              MessageLoaderParms parms("CQL.CQLSelectStatementRep.PROJ_UNINIT",
 518                                  "The embedded object property $0 is uninitialized.",
 519                                  nodeProp.getName().getString());
 520                              throw CQLRuntimeException(parms);
 521                          }
 522                      
 523                          if (!nodeObj.isInstance())
 524                          {
 525                              // Not allowed to project on a Class
 526                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"is a class");
 527                              PEG_METHOD_EXIT();
 528                              MessageLoaderParms parms("CQL.CQLSelectStatementRep.PROJ_CLASS",
 529                                  "CQL does not allow properties to be projected on class $0.",
 530                                  nodeProp.getName().getString());
 531                              throw CQLRuntimeException(parms);
 532 karl            1.18     }
 533                          nodeInst = CIMInstance(nodeObj);
 534 a.dunfey        1.16 #ifdef PEGASUS_EMBEDDED_INSTANCE_SUPPORT
 535 karl            1.18     }
 536 chuck           1.2  
 537 karl            1.18     else if(nodeValType == CIMTYPE_INSTANCE)
 538                          {
 539                              nodeVal.get(nodeInst);
 540                              if (nodeInst.isUninitialized())
 541                              {
 542                                  // Not allowed to project on an uninitialized object
 543                                  PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"is uninitialized");
 544                                  PEG_METHOD_EXIT();
 545                                  MessageLoaderParms parms(
 546                                      "CQL.CQLSelectStatementRep.PROJ_UNINIT",
 547                                      "The embedded object property $0 is uninitialized.",
 548                                      nodeProp.getName().getString());
 549                                  throw CQLRuntimeException(parms);
 550                              }
 551 a.dunfey        1.16     }
 552                      #endif // PEGASUS_EMBEDDED_INSTANCE_SUPPORT
 553 karl            1.18     //
 554                          // Do the projection.
 555                          //
 556                          
 557                          Array<CIMName> requiredProps;
 558                          Boolean allPropsRequired = node->wildcard;
 559                          
 560                          // Loop through the children of the node.
 561                          // The node represents an embedded instance,
 562                          // and the child nodes are the required properties on the embedded instance.
 563                          PropertyNode * curChild = node->firstChild.get();
 564                          while (curChild != NULL)
 565                          {
 566                              PEG_TRACE_STRING (TRC_CQL, 
 567                                  Tracer::LEVEL4,"project childNode = " + curChild->name.getString());
 568                              
 569                              // Determine if the embedded instance meets the class scoping
 570                              // rules for the current child node
 571                              Boolean filterable = isFilterable(nodeInst, curChild);
 572                              
 573                              // Indicates if the child node is still required after the recursive 
 574 karl            1.18         // call.
 575                              Boolean childRequired = true;
 576                              
 577                              // If the embedded instance is filterable, and the child node has 
 578                              // children, or is wildcarded, then the child is assumed to be an 
 579                              // embedded instance, and we need to recurse to apply the projection 
 580                              // on the embedded instance.
 581                              // (the check for embedded instance is done in the recursive call)
 582                              if (filterable &&
 583                                  (curChild->firstChild.get() != NULL || curChild->wildcard))
 584                              {
 585                                  // We need to project on an embedded instance property. 
 586                                  // The steps are to remove the embedded instance property from 
 587                                  // the current instance, project on that embedded instance 
 588                                  // property, and then add the projected
 589                                  // embedded instance property back to the current instance.
 590                                  PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,
 591                                      "about to recurse: " + curChild->name.getString());
 592                                  Uint32 index = nodeInst.findProperty(curChild->name);
 593                                  if (index != PEG_NOT_FOUND)
 594                                  {
 595 karl            1.18                 // The current instance has the required embedded instance 
 596                                      // property.
 597                                      // Note: embedded instance property missing is caught below.
 598                                      
 599                                      // Remove the embedded instance property
 600                                      CIMProperty childProp = nodeInst.getProperty(index);
 601                                      nodeInst.removeProperty(index);
 602                                      
 603                                      // Project onto the embedded instance property.
 604                                      // If the last parameter is true, then the childNode
 605                                      // will not remove properties when filtering the 
 606                                      // embedded instance.
 607                                      // This call returns whether the embedded instance property
 608                                      // should be added to the required property list.
 609                                      Boolean preserve =
 610                                        node->endpoint || allPropsRequired || preservePropsForParent;
 611                                      childRequired = applyProjection(curChild, childProp, preserve, 
 612                                          allowMissing);
 613                                      nodeInst.addProperty(childProp);
 614                                  }
 615                              }
 616 karl            1.18 
 617                              // If the embedded instance is filterable,
 618                              // then add the current child to the list if it is still required.
 619                              if (filterable && childRequired)
 620                              {
 621                                  // The instance is filterable, add the property to the 
 622                                  // required list.
 623                                  PEG_TRACE_STRING (TRC_CQL,
 624                                      Tracer::LEVEL4,"add req prop: " + curChild->name.getString());
 625                                  requiredProps.append(curChild->name);
 626                              }
 627 chuck           1.2  
 628                          curChild = curChild->sibling.get();
 629 karl            1.18     }
 630 chuck           1.2  
 631 karl            1.18     // Filter the instance.
 632                          // This removes unneeded properties, unless this
 633                          // embedded instance node was an endpoint (last element)
 634                          // in a chained identifier.
 635                          // This also checks for missing required properties on the instance.
 636                          Boolean preserveProps = node->endpoint || preservePropsForParent;
 637                          filterInstance(nodeInst,
 638 chuck           1.3                   allPropsRequired,
 639                                       nodeInst.getClassName(),
 640                                       requiredProps,
 641 carolann.graves 1.12                  preserveProps,
 642                                       allowMissing);
 643 chuck           1.2  
 644 karl            1.18     // Put the projected instance back into the property.
 645 a.dunfey        1.16 #ifdef PEGASUS_EMBEDDED_INSTANCE_SUPPORT
 646 karl            1.18     if(nodeValType == CIMTYPE_INSTANCE)
 647                          {
 648                              nodeProp.setValue(nodeInst);
 649                          }
 650                          else
 651 a.dunfey        1.16 #endif
 652 karl            1.18     {
 653                              CIMObject newNodeObj(nodeInst);
 654                              CIMValue newNodeVal(newNodeObj);
 655                              nodeProp.setValue(newNodeVal);
 656                          }
 657 chuck           1.3  
 658 karl            1.18     // Indicate to the caller whether the projected instance
 659                          // is still a required property.  It is required if it is an endpoint
 660                          // (ie. the last element of a chained identifier)
 661                          // OR if it still has properties after being projected
 662                          if (node->endpoint || nodeInst.getPropertyCount() > 0)
 663                          {
 664                              return true;
 665                          }
 666                      
 667                          return false;
 668 david.dillard   1.11 }
 669 chuck           1.2  
 670 kumpf           1.21 Boolean CQLSelectStatementRep::isFilterable(
 671                          const CIMInstance& inst,
 672                          PropertyNode* node) const
 673 chuck           1.2  {
 674 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::isFilterable");
 675                          PEG_TRACE_STRING (TRC_CQL,
 676                            Tracer::LEVEL4,"instance = " + inst.getClassName().getString());
 677                          PEG_TRACE_STRING (TRC_CQL,
 678                            Tracer::LEVEL4,"scope = " + node->scope.getString());
 679                          
 680                          //
 681                          // Determine if an instance is filterable for a scoped property (ie. its
 682                          // type is the scoping class or a subclass of the scoping class where the
 683                          // property exists)
 684                          //
 685                          // Note that an instance that is unfilterable is not considered
 686                          // an error.  In CQL, an instance that is not of the required scope
 687                          // would cause a NULL to be placed in the result set column for the
 688                          // property. However since we are not implementing result set in stage1,
 689                          // just skip the property.  This can lead to an instance having
 690                          // NO required properties even though it is derived from the FROM class.
 691                          // This can easily happen if the scoping operator is used.
 692                          //
 693                          
 694                          Boolean filterable = false;
 695 karl            1.18     if (inst.getClassName() == node->scope)
 696 chuck           1.2      {
 697 karl            1.18         // The instance's class is the same as the required scope
 698                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"instance matches scope");
 699 chuck           1.2          filterable = true;
 700                          }
 701 karl            1.18     else
 702 chuck           1.2      {
 703 karl            1.18         try
 704                              {
 705                                  if (_ctx->isSubClass(node->scope, inst.getClassName()))
 706                                  {
 707                                      // The instance's class is a subclass of the required scope.
 708                                      PEG_TRACE_CSTRING (TRC_CQL,
 709                                          Tracer::LEVEL4,"instance is subclass of scope");
 710                                      filterable = true;
 711                                  }
 712                              }
 713                              catch (const CIMException& ce)
 714                              {
 715                                  if (ce.getCode() == CIM_ERR_INVALID_CLASS ||
 716                                    ce.getCode() == CIM_ERR_NOT_FOUND)
 717                                  {
 718                                      // The scoping class was not found in the schema.
 719                                      // Just swallow this error because according to the
 720                                      // spec we should be putting NULL in the result column,
 721                                      // which means skipping the property on the instance.
 722                                      PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,
 723                                          "scope class not in schema");
 724 karl            1.18             }
 725                                  else
 726                                  {
 727                                      PEG_METHOD_EXIT();
 728                                      throw;
 729                                  }
 730                              }
 731 chuck           1.2      }
 732 karl            1.18     
 733                          PEG_METHOD_EXIT();
 734                          return filterable;
 735 david.dillard   1.11 }
 736 chuck           1.2  
 737 david.dillard   1.11 void CQLSelectStatementRep::filterInstance(CIMInstance& inst,
 738 chuck           1.3                                             Boolean& allPropsRequired,
 739                                                                 const CIMName& allPropsClass,
 740                                                                 Array<CIMName>& requiredProps,
 741 carolann.graves 1.12                                            Boolean& preserveProps,
 742 kumpf           1.21                                            Boolean allowMissing) const
 743 chuck           1.3  {
 744 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::filterInstance");
 745                          PEG_TRACE_STRING (TRC_CQL, 
 746                              Tracer::LEVEL4,"instance = " + inst.getClassName().getString());
 747                          PEG_TRACE_STRING (TRC_CQL, 
 748                              Tracer::LEVEL4,"allPropsClass = " + allPropsClass.getString());
 749                          
 750                          // Implementation note:
 751                          // Scoping operator before a wildcard is not allowed:
 752                          // Example:
 753                          // SELECT fromclass.embobj1.scope1::* FROM fromclass
 754                          //
 755                          // However, the following are allowed:
 756                          // SELECT fromclass.embobj1.* FROM fromclass
 757                          // (this means that all the properties on the class of instance embobj1
 758                          //  are required)
 759                          //
 760                          // SELECT fromclass.* FROM fromclass
 761                          // (this means that all the properties on class fromclass are required
 762                          //  to be on the instance being projected, not including any
 763                          //  properties on a subclass of fromclass)
 764                          
 765 karl            1.18     // If all properties are required (ie. wildcarded), then add
 766                          // all the properties of allPropsClass to the required list.
 767                          // The allPropsClass is either the FROM class or the class of an 
 768                          // embedded instance.
 769                          if (allPropsRequired)
 770                          {
 771                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"all props required");
 772                              CIMClass cls = _ctx->getClass(allPropsClass);
 773                              Array<CIMName> clsProps;
 774                              for (Uint32 i = 0; i < cls.getPropertyCount(); i++)
 775                              {
 776                                  if (!containsProperty(cls.getProperty(i).getName(), requiredProps))
 777                                  {
 778                                      requiredProps.append(cls.getProperty(i).getName());
 779                                  }
 780                              }
 781 chuck           1.2      }
 782 chuck           1.3  
 783 karl            1.18     // Find out what properties are on the instance.
 784                          Array<CIMName> supportedProps;
 785                          for (Uint32 i = 0; i < inst.getPropertyCount(); i++)
 786                          {
 787                              supportedProps.append(inst.getProperty(i).getName());
 788                          }
 789                      
 790                          // Check that all required properties are on the instance.
 791                          if (!allowMissing)
 792                          {
 793                              for (Uint32 i = 0; i < requiredProps.size(); i++)
 794                              {
 795                                  if (!containsProperty(requiredProps[i], supportedProps))
 796                                  {
 797                                      PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"missing:" + 
 798                                          requiredProps[i].getString());
 799                                      PEG_METHOD_EXIT();
 800 karl            1.19                 MessageLoaderParms parms(
 801                                          "CQL.CQLSelectStatementRep.PROJ_MISSING_PROP",
 802 karl            1.18                     "The property $0 is missing on the instance of class $1.",
 803                                          requiredProps[i].getString(),
 804                                          inst.getClassName().getString());
 805                                      throw QueryRuntimePropertyException(parms);
 806                                  }
 807                              }
 808                          }
 809                      
 810                          // If requested, remove the properties on the instance that are not 
 811                          // required.
 812                          if (!preserveProps)
 813                          {
 814                              for (Uint32 i = 0; i < supportedProps.size(); i++)
 815                              {
 816                                  if (!containsProperty(supportedProps[i], requiredProps))
 817                                  {
 818                                      Uint32 index = inst.findProperty(supportedProps[i]);
 819                                      PEGASUS_ASSERT(index != PEG_NOT_FOUND);
 820                                      PEG_TRACE_STRING (TRC_CQL,
 821                                          Tracer::LEVEL4,"removing:" + supportedProps[i].getString());
 822                                      inst.removeProperty(index);
 823 karl            1.18             }
 824                              }
 825                          }
 826                          PEG_METHOD_EXIT();
 827 chuck           1.2  }
 828                      
 829                      //
 830                      // Validates that all the chained identifiers in the statement meet
 831                      // the rules in the CQL spec vs.the class definitions in the repository
 832                      //
 833 david.dillard   1.13 void CQLSelectStatementRep::validate()
 834 chuck           1.2  {
 835 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::validate");
 836                          
 837                          if(_ctx == NULL)
 838                          {
 839                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"null QC");
 840                              PEG_METHOD_EXIT();
 841                              MessageLoaderParms parms(
 842                                  "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
 843                                  "Trying to process a query with a NULL Query Context.");
 844                              throw QueryValidationException(parms);
 845                          }
 846                          
 847                          if (!_contextApplied)
 848                              applyContext();
 849                          
 850                          for (Uint32 i = 0; i < _selectIdentifiers.size(); i++)
 851                          {
 852                              validateProperty(_selectIdentifiers[i]);
 853                          }
 854                          
 855                          Array<QueryChainedIdentifier> _whereIdentifiers = _ctx->getWhereList();
 856 karl            1.18     for (Uint32 i = 0; i < _whereIdentifiers.size(); i++)
 857                          {
 858                              validateProperty(_whereIdentifiers[i]);
 859                          }
 860                          
 861 chuck           1.3      PEG_METHOD_EXIT();
 862 chuck           1.2  }
 863                      
 864                      //
 865                      // Validates that the chained identifier meets all the rules in the CQL
 866                      // spec vs.the class definitions in the repository
 867                      //
 868 kumpf           1.21 void CQLSelectStatementRep::validateProperty(
 869                          const QueryChainedIdentifier& chainId) const
 870 chuck           1.2  {
 871 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::validateProperty");
 872                          
 873                          // Note: applyContext has been called beforehand
 874                          
 875                          Array<QueryIdentifier> ids = chainId.getSubIdentifiers();
 876                          
 877                          Uint32 startingPos = 0;
 878                          CIMName curContext;
 879                          for (Uint32 pos = startingPos; pos < ids.size(); pos++)
 880                          {
 881                              // Determine the current class context
 882                              if (ids[pos].isScoped())
 883                              {
 884                                  // The chain element is scoped.  Use the scoping
 885                                  // class as the current context.  Note: this depends
 886                                  // on applyContext resolving the class aliases before we get here.
 887                                  curContext = CIMName(ids[pos].getScope());
 888                              }
 889                              else
 890                              {
 891                                  // The chain element is not scoped.  Assume that we are
 892 karl            1.18             // before a position that is required to be scoped.
 893                                  // (applyContext validates that the chained identifier
 894                                  // has scoped identifiers in the required positions).
 895                                  // The current context is the name at the first position,
 896                                  // which must be a classname (ie. right side of ISA where
 897                                  // the only element in the chain is a classname, or
 898                                  // cases where the FROM class is the first, and maybe only,
 899                                  // element of the chain).
 900                                  PEGASUS_ASSERT((pos < startingPos + 2) || ids[pos].isWildcard());
 901                                  curContext = ids[0].getName();
 902                              }
 903 chuck           1.3  
 904 karl            1.18         PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"current context: " +
 905                                                 curContext.getString());
 906                              
 907                              // Get the class definition of the current class context
 908                              // Note: keep this code here so that class existence is always
 909                              // checked.  Eg. SELECT * FROM fromClass
 910                              CIMClass classDef;
 911                              try
 912                              {
 913                                  classDef = _ctx->getClass(curContext);
 914                              }
 915                              catch (const CIMException& ce)
 916                              {
 917                                  PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"repository error");
 918                                  PEG_METHOD_EXIT();
 919                                  if (ce.getCode() == CIM_ERR_NOT_FOUND ||
 920                                    ce.getCode() == CIM_ERR_INVALID_CLASS)
 921                                  {
 922                                      MessageLoaderParms parms(
 923 karl            1.19                     "CQL.CQLSelectStatementRep.VAL_CLASS_NOT_EXIST",
 924                                          "The class $0 does not exist.",
 925                                          curContext.getString());
 926 karl            1.18                 throw QueryValidationException(parms);
 927                                  }
 928                                  else
 929                                  {
 930                                      throw;
 931                                  }
 932                              }
 933 david.dillard   1.11 
 934 karl            1.18         // Now do the checks for properties existing on the current 
 935                              // class context
 936                              // and the class relationship rules in section 5.4.1.
 937                              // Only do these checks if the chain id has a property.
 938                              if (pos > startingPos)
 939                              {
 940                                  if (ids[pos].isWildcard())
 941                                  {
 942                                      // The wildcard is at the end (verified by applyContext), so
 943                                      // no checking is required at this position.
 944                                      continue;
 945                                  }
 946                          
 947                                  // Determine if the property name at the current position
 948                                  // exists on the current class context.
 949                                  Uint32 propertyIndex = classDef.findProperty(ids[pos].getName());
 950                                  if (propertyIndex == PEG_NOT_FOUND)
 951                                  {
 952                                      PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,
 953                                          "prop not on context " +
 954                                          ids[pos].getName().getString());
 955 karl            1.18                 PEG_METHOD_EXIT();
 956                                      MessageLoaderParms parms(
 957                                          "CQL.CQLSelectStatementRep.VAL_PROP_NOT_ON_CLASS",
 958                                          "The property $0 does not exist on class $1.",
 959                                          ids[pos].getName().getString(), 
 960                                          classDef.getClassName().getString());
 961                                      throw QueryMissingPropertyException(parms);
 962                                  }
 963                          
 964                                  // Checking class relationship rules in section 5.4.1.
 965                                  // For validateProperties, this only applies to the first
 966                                  // property in the chain.  This is because once we get into
 967                                  // embedded properties we don't know what the class will be
 968                                  // until we have an instance.
 969                                  if ((pos == (startingPos+1)) && !curContext.equal(ids[0].getName()))
 970                                  {
 971                                      // Its the first property, and the class context is not 
 972                                      // the FROM class.
 973                                      // Check the class relationship between the scoping class and 
 974                                      // the FROM class.
 975                                      if (_ctx->getClassRelation(ids[0].getName(), curContext) == 
 976 karl            1.18                         QueryContext::NOTRELATED)
 977                                      {
 978                                          PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,
 979                                              "scope violation for:"+
 980                                              ids[0].getName().getString());
 981                                          PEG_METHOD_EXIT();
 982                                          MessageLoaderParms parms(
 983                                            "CQL.CQLSelectStatementRep.VAL_SCOPE_VIOLATION",
 984                                            "The class $0 is not a superclass, subclass, or the same"
 985                                            " class as $1.",
 986                                            curContext.getString(), ids[0].getName().getString());
 987                                          throw QueryValidationException(parms);
 988                                      }
 989                                  }
 990                          
 991                                  // If the current position implies an embedded object, then
 992                                  // verify that the property is an embedded object
 993                                  if ((pos > startingPos) && (pos < (ids.size() - 1)))
 994                                  {
 995                                      CIMProperty embObj = classDef.getProperty(propertyIndex);
 996                                      CIMName qual("EmbeddedObject");
 997 karl            1.18                 if (embObj.findQualifier(qual) == PEG_NOT_FOUND)
 998                                      {
 999                                          PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"prop not emb " +
1000                                                          embObj.getName().getString());
1001                                          PEG_METHOD_EXIT();
1002                                          MessageLoaderParms parms(
1003                                              "CQL.CQLSelectStatementRep.PROP_NOT_EMB",
1004                                              "The property $0 must be an embedded object.",
1005                                              embObj.getName().getString());
1006                                          throw QueryValidationException(parms);
1007                                      }
1008                                  }
1009 chuck           1.2          }
1010                          }
1011 david.dillard   1.11 
1012 chuck           1.3    PEG_METHOD_EXIT();
1013 chuck           1.2  }
1014                      
1015 kumpf           1.21 CIMName CQLSelectStatementRep::lookupFromClass(const String& lookup) const
1016 chuck           1.2  {
1017 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::lookupFromClass");
1018                          
1019                          QueryIdentifier id = _ctx->findClass(lookup);
1020                          
1021                          PEG_METHOD_EXIT();
1022                          
1023                          return id.getName();
1024 chuck           1.2  }
1025                      
1026 kumpf           1.21 Array<CIMObjectPath> CQLSelectStatementRep::getClassPathList() const
1027 chuck           1.2  {
1028 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::getClassPathList");
1029                          
1030                          if(_ctx == NULL)
1031                          {
1032                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"null QC");
1033                              PEG_METHOD_EXIT();
1034                              MessageLoaderParms parms(
1035                                  "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
1036                                  "Trying to process a query with a NULL Query Context.");
1037                              throw CQLRuntimeException(parms);
1038                          }
1039                          
1040                          Array<QueryIdentifier> ids = _ctx->getFromList();
1041                          PEGASUS_ASSERT(ids.size() == 1);  // no joins yet
1042                          
1043                          // No wbem-uri support yet.
1044                          CIMObjectPath path(String::EMPTY, _ctx->getNamespace(), ids[0].getName());
1045                          
1046                          Array<CIMObjectPath> paths;
1047                          paths.append(path);
1048                          
1049 karl            1.18     PEG_METHOD_EXIT();
1050                          
1051                          return paths;
1052 chuck           1.3  
1053 chuck           1.2  }
1054                      
1055 karl            1.18 CIMPropertyList CQLSelectStatementRep::getPropertyList(
1056                          const CIMObjectPath& inClassName)
1057 chuck           1.2  {
1058 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::getPropertyList");
1059                          try
1060 chuck           1.5      {
1061 karl            1.18         return getPropertyListInternal(inClassName, true, true);
1062 chuck           1.5      }
1063 karl            1.18     catch (const CIMException& ce)
1064 chuck           1.5      {
1065 karl            1.18         PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"cim exception");
1066                              PEG_METHOD_EXIT();
1067                              if (ce.getCode() == CIM_ERR_NOT_FOUND ||
1068                                  ce.getCode() == CIM_ERR_INVALID_CLASS)
1069                              {
1070                                  MessageLoaderParms parms(
1071                                      "CQL.CQLSelectStatementRep.GPL_CLASS_NOT_EXIST",
1072                                      "A class required to determine the property list was"
1073                                          " not found.");
1074                                  throw CQLRuntimeException(parms);
1075                              }
1076                              else
1077                              {
1078                                  throw;
1079                              }
1080 chuck           1.5      }
1081 chuck           1.2  }
1082                      
1083 karl            1.18 CIMPropertyList CQLSelectStatementRep::getSelectPropertyList(
1084                          const CIMObjectPath& inClassName)
1085 chuck           1.2  {
1086 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::getSelectPropertyList");
1087                          try
1088 chuck           1.5      {
1089 karl            1.18         return getPropertyListInternal(inClassName, true, false);
1090 chuck           1.5      }
1091 karl            1.18     catch (const CIMException& ce)
1092 chuck           1.5      {
1093 karl            1.18         PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"cim exception");
1094                              PEG_METHOD_EXIT();
1095                              if (ce.getCode() == CIM_ERR_NOT_FOUND ||
1096                                  ce.getCode() == CIM_ERR_INVALID_CLASS)
1097                              {
1098                                  MessageLoaderParms parms(
1099                                      "CQL.CQLSelectStatementRep.GPL_CLASS_NOT_EXIST",
1100                                      "A class required to determine the property list was"
1101                                          " not found.");
1102                                  throw CQLRuntimeException(parms);
1103                              }
1104                              else
1105                              {
1106                                  throw;
1107                              }
1108 chuck           1.5      }
1109 chuck           1.2  }
1110                      
1111 karl            1.18 CIMPropertyList CQLSelectStatementRep::getWherePropertyList(
1112                          const CIMObjectPath& inClassName)
1113 chuck           1.2  {
1114 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::getWherePropertyList");
1115                          try
1116 chuck           1.5      {
1117 karl            1.18         return getPropertyListInternal(inClassName, false, true);
1118 chuck           1.5      }
1119 karl            1.18     catch (const CIMException& ce)
1120 chuck           1.5      {
1121 karl            1.18         PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"cim exception");
1122                              PEG_METHOD_EXIT();
1123                              if (ce.getCode() == CIM_ERR_NOT_FOUND ||
1124                                  ce.getCode() == CIM_ERR_INVALID_CLASS)
1125                              {
1126                                  MessageLoaderParms parms(
1127                                      "CQL.CQLSelectStatementRep.GPL_CLASS_NOT_EXIST",
1128                                      "A class required to determine the property list was"
1129                                          " not found.");
1130                                  throw CQLRuntimeException(parms);
1131                              }
1132                              else
1133                              {
1134                                  throw;
1135                              }
1136 chuck           1.5      }
1137 chuck           1.2  }
1138                      
1139 karl            1.18 CIMPropertyList CQLSelectStatementRep::getPropertyListInternal(
1140                          const CIMObjectPath& inClassName,
1141                          Boolean includeSelect,
1142                          Boolean includeWhere)
1143                      {
1144                          PEG_METHOD_ENTER (TRC_CQL, 
1145                              "CQLSelectStatementRep::getPropertyListInternal");
1146                          
1147                          if(_ctx == NULL)
1148                          {
1149                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"null QC");
1150                              PEG_METHOD_EXIT();
1151                              MessageLoaderParms parms(
1152                                  "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
1153                                  "Trying to process a query with a NULL Query Context.");
1154                              throw CQLRuntimeException(parms);
1155                          }
1156                          
1157                          if (!_contextApplied)
1158                              applyContext();
1159                          
1160 karl            1.18     // Get the FROM class.
1161                          CIMName fromClass = _ctx->getFromList()[0].getName();
1162                          
1163                          // Get the classname passed in.  Note: since wbem-uri is not supported yet,
1164                          // only use the classname part of the path.
1165                          CIMName className = inClassName.getClassName();
1166                          if (className.isNull())
1167                          {
1168                              // If the caller passed in an empty className, then the
1169                              // FROM class is to be used.
1170                              className = fromClass;
1171                          }
1172                          else
1173                          {
1174                              // The caller passed in some class name.  Verify that it is the FROM
1175                              // class or a subclass of the FROM class.
1176                              if(!(className == fromClass))
1177                              {
1178                                  // Check if subclass of the FROM class
1179                                  if(!_ctx->isSubClass(fromClass, className))
1180                                  {
1181 karl            1.18                 MessageLoaderParms parms(
1182                                          "CQL.CQLSelectStatementRep.CLASS_NOT_FROM_LIST_CLASS",
1183                                          "Class $0 does not match the FROM class or any of its"
1184                                              " subclasses.",
1185                                          className.getString());
1186                                      throw CQLRuntimeException(parms);
1187                                  }
1188                              }
1189                          }
1190 chuck           1.3  
1191 karl            1.18     Boolean isWildcard;
1192                          Array<CIMName> reqProps;
1193                          Array<CIMName> matchedScopes;
1194                          Array<CIMName> unmatchedScopes;
1195                          
1196                          // Add required properties from the select list.
1197                          if (includeSelect)
1198                          {
1199                              for (Uint32 i = 0; i < _selectIdentifiers.size(); i++)
1200                              {
1201                                  isWildcard = addRequiredProperty(reqProps,
1202                                                                 className,
1203                                                                 _selectIdentifiers[i],
1204                                                                 matchedScopes,
1205                                                                 unmatchedScopes);
1206                                  
1207                                  if (isWildcard)
1208                                  {
1209                                      // This indicates that a wildcard was found,
1210                                      // and the class passed in was the FROM class.
1211                                      // Return null property list to indicate all 
1212 karl            1.18                 // properties required.
1213                                      return CIMPropertyList();
1214                                  }
1215                              }
1216                          }
1217 chuck           1.2  
1218 karl            1.18     // Add required properties from the WHERE clause.
1219                          if (includeWhere)
1220                          {
1221                              Array<QueryChainedIdentifier> _whereIdentifiers = _ctx->getWhereList();
1222                              for (Uint32 i = 0; i < _whereIdentifiers.size(); i++)
1223                              {
1224                                  isWildcard = addRequiredProperty(reqProps,
1225                                                                 className,
1226                                                                 _whereIdentifiers[i],
1227                                                                 matchedScopes,
1228                                                                 unmatchedScopes);
1229                                  
1230                                  // Wildcards are not allowed in the WHERE clause
1231                                  PEGASUS_ASSERT(!isWildcard);
1232                              }
1233                          }
1234                          
1235                          // Check if every property on the class is required.
1236                          CIMClass theClass = _ctx->getClass(className);
1237                          Uint32 propCnt = theClass.getPropertyCount();
1238                          Boolean allProps = true;
1239 karl            1.18     for (Uint32 i = 0; i < propCnt; i++)
1240                          {
1241                              if (!containsProperty(theClass.getProperty(i).getName(), reqProps))
1242                              {
1243                                  allProps = false;
1244                                  break;
1245                              }
1246 david.dillard   1.11     }
1247                      
1248 karl            1.18     if (allProps)
1249 chuck           1.2      {
1250 karl            1.18         // Return null property list to indicate all properties are required.
1251                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"all props req");
1252                              PEG_METHOD_EXIT();
1253 chuck           1.2          return CIMPropertyList();
1254                          }
1255 karl            1.18     else
1256 chuck           1.2      {
1257 karl            1.18         // Return the required property list.  
1258                              // Note that it is possible to return
1259                              // an empty list in the case of no required properties for the classname
1260                              // passed in.  This can happen when the scoping operator is used.
1261                              PEG_METHOD_EXIT();
1262                              return CIMPropertyList(reqProps);
1263                          }
1264 chuck           1.2  }
1265                      
1266 kumpf           1.21 Boolean CQLSelectStatementRep::addRequiredProperty(
1267                          Array<CIMName>& reqProps,
1268                          const CIMName& className,
1269                          const QueryChainedIdentifier& chainId,
1270 karl            1.18     Array<CIMName>& matchedScopes,
1271 kumpf           1.21     Array<CIMName>& unmatchedScopes) const
1272 karl            1.18 {
1273                          PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::addRequiredProperty");
1274                          
1275                          //
1276                          // Implementation notes:
1277                          // This function does not look for required properties on embedded objects.
1278                          // This function assumes that applyContext has been called.
1279                          //
1280                          
1281                          Array<QueryIdentifier> ids = chainId.getSubIdentifiers();
1282                          
1283                          // After applyContext has been called, a single element
1284                          // chained identifier refers to either an instance of the
1285                          // FROM class, or is the classname on the right side of ISA.
1286                          if (ids.size() == 1)
1287                          {
1288                              // This identifier is not a property name
1289                              PEG_METHOD_EXIT();
1290                              return false;
1291 chuck           1.2      }
1292 karl            1.18     
1293                          PEG_TRACE_STRING(TRC_CQL, Tracer::LEVEL4,"id[1] = " + ids[1].toString());
1294                          
1295                          if (ids[1].isSymbolicConstant())
1296                          {
1297                              // Non-embedded symbolic constants are not properties
1298                              // Note that an embedded symbolic constant like this:
1299                              // fromclass.embobj.scope::someprop#'ok'
1300                              // implies that embobj is a required property, because
1301                              // embobj could be null, and that affects how the
1302                              // identifier is evaluated.
1303 chuck           1.3          PEG_METHOD_EXIT();
1304 chuck           1.2          return false;
1305 karl            1.18     }
1306 chuck           1.3  
1307 karl            1.18     // Since applyContext has been called, the first chain element
1308                          // will be the FROM class, so go to the 2nd chain element.
1309                          if (ids[1].isScoped())
1310                          {
1311                              // The 2nd chain element is a scoped property.
1312                              // Eg. fromclass.someclass::someprop
1313                              
1314                              // Determine the class that the property is being scoped to.
1315                              // This could be the FROM class, or some other class not in 
1316                              // the FROM list
1317                              CIMName scopingClass = CIMName(ids[1].getScope());
1318                              
1319                              // Check if the scoping class is the same as the class passed in.
1320                              if (scopingClass == className)
1321 chuck           1.2          {
1322 karl            1.18             // The scoping class is the same as the class passed,
1323                                  // add the property if not already added
1324                                  if (!containsProperty(ids[1].getName(), reqProps))
1325                                  {
1326                                      reqProps.append(ids[1].getName());
1327                                  }
1328 chuck           1.2          }
1329 karl            1.18         else
1330                              {
1331                                  // The scoping class is not the same as the class passed in.
1332                                  // Check if we already know that the scoping class is a subclass
1333                                  // of the class passed in
1334                                  if (containsProperty(scopingClass, unmatchedScopes))
1335                                  {
1336                                      // Scoping class is a subclass.
1337                                      PEG_TRACE_CSTRING(TRC_CQL, Tracer::LEVEL4,
1338                                          "scoping class is a subclass");
1339                                      PEG_METHOD_EXIT();
1340                                      return false;
1341                                  }
1342                      
1343                                  // Check if we already know that the scoping class is a superclass
1344                                  // of the class passed in
1345                                  Boolean isSuper = false;
1346                                  if (containsProperty(scopingClass, matchedScopes))
1347                                  {
1348                                      // Scoping class is a superclass.
1349                                      isSuper = true;
1350 karl            1.18             }
1351                      
1352                                  // Check if the scoping class is a superclass of the class passed in
1353                                  if (isSuper || _ctx->isSubClass(scopingClass, className))
1354                                  {
1355                                      PEG_TRACE_CSTRING (TRC_CQL, 
1356                                          Tracer::LEVEL4,"scoping class is a superclass");
1357                                  
1358                                  // Scoping class is a superclass of the class passed in.
1359                                  if (!isSuper)
1360                                  {
1361                                      // Save this information
1362                                      matchedScopes.append(scopingClass);
1363                                  }
1364                                  
1365                                  // Add to the required property list if not already there.
1366                                  if (!containsProperty(ids[1].getName(), reqProps))
1367                                  {
1368                                      reqProps.append(ids[1].getName());
1369                                  }
1370                                  }
1371 karl            1.18             else
1372                                  {
1373                                      PEG_TRACE_CSTRING (TRC_CQL, 
1374                                          Tracer::LEVEL4,"scoping class is NOT a superclass");
1375                                      
1376                                      // Scoping class is not superclass of class passed in.
1377                                      // Save this information.
1378                                      unmatchedScopes.append(scopingClass);
1379                                  }
1380                              }  // end else scoping class not == class passed in
1381                          }  // end if first id is scoped
1382                          else
1383                          {
1384                              // The 2nd chain element is an unscoped property
1385                              // Check if it is wildcarded
1386                              if (ids[1].isWildcard())
1387 david.dillard   1.11         {
1388 karl            1.18             // Wildcard.
1389                                  // If the class passed in is the FROM class, then
1390                                  // all properties are required on the class passed in.
1391                                  CIMName fromClassName = _ctx->getFromList()[0].getName();
1392                                  if (fromClassName == className)
1393                                  {
1394                                      PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,
1395                                          "wildcard and = FROM");
1396                                      PEG_METHOD_EXIT();
1397                                      return true;
1398                                  }
1399                              
1400                                  // Add all the properties on the FROM class to
1401                                  // the required property list.
1402                                  CIMClass fromClass = _ctx->getClass(fromClassName);
1403                                  for (Uint32 n = 0; n < fromClass.getPropertyCount(); n++)
1404                                  {
1405                                      // Add to the required property list if not already there.
1406                                      if (!containsProperty(fromClass.getProperty(n).getName(), 
1407                                                            reqProps))
1408                                      {
1409 karl            1.18                   reqProps.append(fromClass.getProperty(n).getName());
1410                                      }
1411                                  }
1412                              
1413                                  PEG_METHOD_EXIT();
1414                                  return false;
1415 chuck           1.2          }
1416 karl            1.18         // Implementation note:
1417                              // Since this API assumes that the class passed in
1418                              // is the FROM class or a subclass of the FROM class,
1419                              // AND validateProperties can be called to check if
1420                              // unscoped properties are on the FROM class,
1421                              // we can just add the required property because
1422                              // it is assumed to be on the FROM class.
1423                          
1424 chuck           1.2          // Add to the required property list if not already there.
1425 karl            1.18         if (!containsProperty(ids[1].getName(), reqProps))
1426 david.dillard   1.11         {
1427 karl            1.18             reqProps.append(ids[1].getName());
1428 david.dillard   1.11         }
1429 chuck           1.2      }
1430 karl            1.18     
1431                          // Indicate the required property is not a wildcard
1432                          PEG_METHOD_EXIT();
1433                          return false;
1434 chuck           1.2  }
1435                      
1436                      Array<CQLChainedIdentifier> CQLSelectStatementRep::getSelectChainedIdentifiers()
1437                      {
1438 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, 
1439                              "CQLSelectStatementRep::getSelectChainedIdentifiers");
1440                          
1441                          if (!_contextApplied)
1442                              applyContext();
1443                          
1444                          PEG_METHOD_EXIT();
1445                          
1446                          return _selectIdentifiers;
1447 chuck           1.2  }
1448                      
1449                      Array<CQLChainedIdentifier> CQLSelectStatementRep::getWhereChainedIdentifiers()
1450                      {
1451 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, 
1452                              "CQLSelectStatementRep::getWhereChainedIdentifiers");
1453                          
1454                          if(_ctx == NULL)
1455 chuck           1.2      {
1456 karl            1.18         PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"null QC");
1457                              PEG_METHOD_EXIT();
1458                              MessageLoaderParms parms(
1459                                  "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
1460                                  "Trying to process a query with a NULL Query Context.");
1461                              throw CQLRuntimeException(parms);
1462 chuck           1.2      }
1463 karl            1.18     
1464                          if (!_contextApplied)
1465                              applyContext();
1466                          
1467                          Array<QueryChainedIdentifier> qChainIds = _ctx->getWhereList();
1468                          Array<CQLChainedIdentifier> cqlChainIds;
1469                          for (Uint32 i = 0; i < qChainIds.size(); i++)
1470                          {
1471                              Array<QueryIdentifier> qSubs = qChainIds[i].getSubIdentifiers();
1472                              CQLChainedIdentifier cqlChainId;
1473                              for (Uint32 j = 0; j < qSubs.size(); j++)
1474                              {
1475                                cqlChainId.append(qSubs[j]);
1476                              }
1477                          
1478 chuck           1.2      cqlChainIds.append(cqlChainId);
1479 karl            1.18     }
1480                          
1481                          PEG_METHOD_EXIT();
1482                          
1483                          return cqlChainIds;
1484 chuck           1.2  }
1485                      
1486 kumpf           1.21 Boolean CQLSelectStatementRep::containsProperty(
1487                          const CIMName& name,
1488                          const Array<CIMName>& props)
1489 chuck           1.2  {
1490 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::containsProperty");
1491                          
1492                          for (Uint32 i = 0; i < props.size(); i++)
1493 chuck           1.2      {
1494 karl            1.18         if (props[i] == name)
1495                              {
1496                                  PEG_METHOD_EXIT();
1497                                  return true;
1498                              }
1499 chuck           1.2      }
1500 karl            1.18     
1501                          PEG_METHOD_EXIT();
1502                          return false;
1503 chuck           1.2  }
1504                      
1505 chuck           1.7  //
1506                      // Checks if the classname passed in is the FROM class, or
1507                      // a subclass of the FROM class
1508                      //
1509 kumpf           1.21 Boolean CQLSelectStatementRep::isFromChild(const CIMName& className) const
1510 chuck           1.7  {
1511 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::isFromChild");
1512                          
1513                          QueryContext::ClassRelation rel =
1514                              _ctx->getClassRelation(_ctx->getFromList()[0].getName(), className);
1515                          
1516                          PEG_METHOD_EXIT();
1517 kumpf           1.21     return (rel == QueryContext::SAMECLASS || rel == QueryContext::SUBCLASS);
1518 chuck           1.7  }
1519                      
1520 chuck           1.2  void CQLSelectStatementRep::appendClassPath(const CQLIdentifier& inIdentifier)
1521                      {
1522 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::appendClassPath");
1523                          
1524                          if(_ctx == NULL)
1525                          {
1526                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"null QC");
1527                              PEG_METHOD_EXIT();
1528                              MessageLoaderParms parms(
1529                                  "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
1530                                  "Trying to process a query with a NULL Query Context.");
1531                              throw QueryValidationException(parms);
1532                          }
1533                          _ctx->insertClassPath(inIdentifier);
1534                          
1535 chuck           1.3      PEG_METHOD_EXIT();
1536 chuck           1.2  }
1537                      
1538                      void CQLSelectStatementRep::setPredicate(const CQLPredicate& inPredicate)
1539                      {
1540 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::setPredicate");
1541                          _predicate = inPredicate;
1542                          PEG_METHOD_EXIT();
1543 chuck           1.2  }
1544                      
1545                      CQLPredicate CQLSelectStatementRep::getPredicate() const
1546                      {
1547 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::getPredicate");
1548                          return _predicate;
1549 chuck           1.2  }
1550                      
1551 karl            1.18 void CQLSelectStatementRep::insertClassPathAlias(
1552                          const CQLIdentifier& inIdentifier,
1553 kumpf           1.23     const String& inAlias)
1554 chuck           1.2  {
1555 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::insertClassPathAlias");
1556                          
1557                          if(_ctx == NULL)
1558                          {
1559                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"null QC");
1560                              PEG_METHOD_EXIT();
1561                              MessageLoaderParms parms(
1562                                  "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
1563                                  "Trying to process a query with a NULL Query Context.");
1564                              throw QueryValidationException(parms);
1565                          }
1566                          _ctx->insertClassPath(inIdentifier,inAlias);
1567                          
1568 chuck           1.3      PEG_METHOD_EXIT();
1569 chuck           1.2  }
1570                      
1571 karl            1.18 void CQLSelectStatementRep::appendSelectIdentifier(
1572                          const CQLChainedIdentifier& x)
1573 chuck           1.2  {
1574 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::appendSelectIdentifier");
1575                          _selectIdentifiers.append(x);
1576                          PEG_METHOD_EXIT();
1577 chuck           1.2  }
1578 karl            1.18     
1579 chuck           1.2  void CQLSelectStatementRep::applyContext()
1580                      {
1581 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::applyContext");
1582                          
1583 kumpf           1.21     if (_ctx == NULL)
1584 karl            1.18     {
1585 kumpf           1.21         PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"null QC");
1586                              PEG_METHOD_EXIT();
1587                              MessageLoaderParms parms(
1588                                  "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
1589                                  "Trying to process a query with a NULL Query Context.");
1590                              // throw syntax error to be consistent
1591                              throw CQLSyntaxErrorException(parms);
1592 karl            1.18     }
1593                          
1594                          for (Uint32 i = 0; i < _selectIdentifiers.size(); i++)
1595                          {
1596 kumpf           1.21         _selectIdentifiers[i].applyContext(*_ctx);
1597                              checkWellFormedIdentifier(_selectIdentifiers[i], true);
1598 karl            1.18     }
1599                          
1600                          if (hasWhereClause())
1601                          {
1602 kumpf           1.21         _predicate.applyContext(*_ctx);
1603 karl            1.18     
1604 kumpf           1.21         // Note: must be after call to predicate's applyContext
1605                              Array<QueryChainedIdentifier> _whereIdentifiers = _ctx->getWhereList();
1606                              for (Uint32 i = 0; i < _whereIdentifiers.size(); i++)
1607                              {
1608                                  checkWellFormedIdentifier(_whereIdentifiers[i], false);
1609                              }
1610 karl            1.18     }
1611                          
1612                          _contextApplied = true;
1613                          PEG_METHOD_EXIT();
1614 chuck           1.2  }
1615                      
1616 karl            1.18 void CQLSelectStatementRep::checkWellFormedIdentifier(
1617                          const QueryChainedIdentifier& chainId,
1618                          Boolean isSelectListId)
1619                      {
1620                          PEG_METHOD_ENTER (TRC_CQL, 
1621                            "CQLSelectStatementRep::checkWellFormedIdentifier");
1622                          
1623                          // This function assumes that applyContext has been called.
1624                          Array<QueryIdentifier> ids = chainId.getSubIdentifiers();
1625                          
1626                          if (ids.size() == 0)
1627 chuck           1.2      {
1628 karl            1.18         PEG_METHOD_EXIT();
1629                              MessageLoaderParms parms("CQL.CQLSelectStatementRep.EMPTY_CHAIN",
1630                                                       "An empty chained identifier was found.");
1631                              throw CQLSyntaxErrorException(parms);
1632 chuck           1.2      }
1633 karl            1.18     
1634                          PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"chain =" + chainId.toString());
1635                          
1636                          if (ids.size() == 1 && isSelectListId)
1637 chuck           1.2      {
1638 karl            1.18         // Single element chain ids are not allow in the select list.
1639                              // The select list can only have properties.
1640                              PEG_METHOD_EXIT();
1641                              MessageLoaderParms parms(
1642                                  "CQL.CQLSelectStatementRep.SINGLE_CHID_IN_SELECT",
1643                                  "A property on the FROM class must be selected.");
1644                              throw CQLSyntaxErrorException(parms);
1645 chuck           1.2      }
1646                      
1647 karl            1.18     if (ids[0].isScoped()
1648                              || ids[0].isWildcard()
1649                              || ids[0].isSymbolicConstant()
1650                              || ids[0].isArray())
1651 chuck           1.2      {
1652 karl            1.18         // The first identifier must be a classname (it could be the FROM
1653                              // class, or some other class for the right side of ISA)
1654                              PEG_METHOD_EXIT();
1655                              MessageLoaderParms parms("CQL.CQLSelectStatementRep.FIRST_ID_ILLEGAL",
1656                                                       "The chained identifier $0 is illegal.",
1657                                                       chainId.toString());
1658                              throw CQLSyntaxErrorException(parms);
1659 chuck           1.2      }
1660                      
1661 karl            1.18     Uint32 startingPos = 1;
1662                          for (Uint32 pos = startingPos; pos < ids.size(); pos++)
1663 chuck           1.2      {
1664 karl            1.18         if (ids[pos].isArray() && isSelectListId)
1665                              {
1666                                  PEG_METHOD_EXIT();
1667                                  MessageLoaderParms parms(
1668                                      "CQL.CQLSelectStatementRep.ARRAY_IN_SELECT",
1669                                      "The identifier $0 of $1 in the SELECT list cannot use"
1670                                          " an array index.",
1671                                      ids[pos].toString(), chainId.toString());
1672                                  throw CQLSyntaxErrorException(parms);
1673                              }
1674                      
1675                              if (ids[pos].isSymbolicConstant() && isSelectListId)
1676                              {
1677                                  PEG_METHOD_EXIT();
1678                                  MessageLoaderParms parms(
1679                                      "CQL.CQLSelectStatementRep.SYMCONST_IN_SELECT",
1680                                      "The identifier $0 of $1 in the SELECT list cannot use a"
1681                                      " symbolic constant.",
1682                                      ids[pos].toString(), chainId.toString());
1683                                  throw CQLSyntaxErrorException(parms);
1684                              }
1685 karl            1.18 
1686                              if (ids[pos].isSymbolicConstant() && pos != (ids.size() -1))
1687                              {
1688                                  PEG_METHOD_EXIT();
1689                                  MessageLoaderParms parms(
1690                                      "CQL.CQLSelectStatementRep.SYMCONST_NOT_LAST",
1691                                      "The symbolic constant identifier $0 of $1 must be the"
1692                                          " last element.",
1693                                      ids[pos].toString(), chainId.toString());
1694                                  throw CQLSyntaxErrorException(parms);
1695                              }
1696 chuck           1.2  
1697 karl            1.18         if (ids[pos].isWildcard())
1698                              {
1699                                  if ( !isSelectListId)
1700                                  {
1701                                      PEG_METHOD_EXIT();
1702                                      MessageLoaderParms parms(
1703                                          "CQL.CQLSelectStatementRep.WILD_IN_WHERE",
1704                                          "The identifier $0 of $1 in the WHERE list cannot use a"
1705                                              " wildcard.",
1706                                          ids[pos].toString(), chainId.toString());
1707                                      throw CQLSyntaxErrorException(parms);
1708                                  }
1709                                  
1710                                  if ( pos != ids.size() - 1)
1711                                  {
1712                                      PEG_METHOD_EXIT();
1713                                      MessageLoaderParms parms(
1714                                          "CQL.CQLSelectStatementRep.WILD_NOT_END",
1715                                          "The wildcard identifier $0 of $1 must be the last"
1716                                              " element.",
1717                                          ids[pos].toString(), chainId.toString());
1718 karl            1.18                 throw CQLSyntaxErrorException(parms);
1719                                  }
1720                              }
1721 chuck           1.2  
1722 karl            1.18         if (pos > startingPos && !ids[pos].isWildcard())
1723                              {
1724                                  if (!ids[pos].isScoped())
1725                                  {
1726                                      PEG_METHOD_EXIT();
1727                                      MessageLoaderParms parms(
1728                                          "CQL.CQLSelectStatementRep.EMB_PROP_NOT_SCOPED",
1729                                          "The identifier $0 of $1 must use the scope operator.",
1730                                          ids[pos].toString(), chainId.toString());
1731                                      throw CQLSyntaxErrorException(parms);
1732                                  }
1733                              }
1734 chuck           1.2      }
1735 karl            1.18     
1736                          PEG_METHOD_EXIT();
1737 chuck           1.2  }
1738                      
1739                      void CQLSelectStatementRep::normalizeToDOC()
1740                      {
1741 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::normalizeToDOC");
1742                          
1743                          if (!_contextApplied)
1744                              applyContext();
1745                          
1746                          if(_hasWhereClause)
1747                          {
1748                              Cql2Dnf DNFer(_predicate);
1749                              _predicate = DNFer.getDnfPredicate();
1750                          }
1751                          
1752                          PEG_METHOD_EXIT();
1753 chuck           1.2  }
1754                      
1755 kumpf           1.21 String CQLSelectStatementRep::toString() const
1756 chuck           1.2  {
1757 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::toString");
1758                          
1759                          if(_ctx == NULL)
1760                          {
1761                              PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"null QC");
1762                              PEG_METHOD_EXIT();
1763                              MessageLoaderParms parms(
1764                                  "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
1765                                  "Trying to process a query with a NULL Query Context.");
1766                              throw CQLRuntimeException(parms);
1767                          }
1768                          
1769                          String s("SELECT ");
1770                          for(Uint32 i = 0; i < _selectIdentifiers.size(); i++)
1771                          {
1772                              if((i > 0) && (i < _selectIdentifiers.size()))
1773                              {
1774                                  s.append(",");
1775                              }
1776                              s.append(_selectIdentifiers[i].toString());
1777                          }
1778 karl            1.18     
1779                          s.append(" ");
1780                          s.append(_ctx->getFromString());
1781                          
1782                          if(_hasWhereClause)
1783                          {
1784                              s.append(" WHERE ");
1785                              s.append(_predicate.toString());
1786                          }
1787                          
1788 chuck           1.3      PEG_METHOD_EXIT();
1789 karl            1.18     return s;
1790 chuck           1.2  }
1791                      
1792                      void CQLSelectStatementRep::setHasWhereClause()
1793                      {
1794 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::setHasWhereClause");
1795                          _hasWhereClause = true;
1796                          PEG_METHOD_EXIT();
1797 chuck           1.2  }
1798                      
1799 kumpf           1.21 Boolean CQLSelectStatementRep::hasWhereClause() const
1800 chuck           1.2  {
1801 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::hasWhereClause");
1802                          return _hasWhereClause;
1803 chuck           1.2  }
1804                      
1805                      void  CQLSelectStatementRep::clear()
1806                      {
1807 karl            1.18     PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::clear");
1808                          
1809 carolann.graves 1.12     if(_ctx == NULL)
1810                          {
1811 karl            1.18          PEG_TRACE_CSTRING (TRC_CQL, Tracer::LEVEL4,"null QC");
1812                               PEG_METHOD_EXIT();
1813                               MessageLoaderParms parms(
1814                                   "CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL",
1815                                   "Trying to process a query with a NULL Query Context.");
1816                               throw CQLRuntimeException(parms);
1817                          }
1818                          
1819                          _ctx->clear();
1820                          _hasWhereClause = false;
1821                          _contextApplied = false;
1822                          _predicate = CQLPredicate();
1823                          _selectIdentifiers.clear();
1824                          
1825                          PEG_METHOD_EXIT();
1826 chuck           1.2  }
1827                      
1828                      PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2