📄 cqlselectstatementrep.cpp
字号:
//%2006//////////////////////////////////////////////////////////////////////////// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;// IBM Corp.; EMC Corporation, The Open Group.// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;// EMC Corporation; VERITAS Software Corporation; The Open Group.// Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;// EMC Corporation; Symantec Corporation; The Open Group.//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to// deal in the Software without restriction, including without limitation the// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or// sell copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions:// // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.////==============================================================================//// Authors: David Rosckes (rosckes@us.ibm.com)// Bert Rivero (hurivero@us.ibm.com)// Chuck Carmack (carmack@us.ibm.com)// Brian Lucier (lucier@us.ibm.com)//// Modified By: David Dillard, VERITAS Software Corp.// (david.dillard@veritas.com)////%/////////////////////////////////////////////////////////////////////////////#include "CQLSelectStatement.h"#include "CQLSelectStatementRep.h"#include <Pegasus/Common/CIMValue.h>#include <Pegasus/Common/CIMInstance.h>#include <Pegasus/Common/CIMProperty.h>#include <Pegasus/Query/QueryCommon/QueryException.h>#include <Pegasus/Query/QueryCommon/QueryIdentifier.h>#include <Pegasus/Query/QueryCommon/QueryChainedIdentifier.h>#include <Pegasus/Common/Tracer.h>#include <Pegasus/Common/InternalException.h>#include <Pegasus/Common/CIMStatusCode.h>#include <Pegasus/Common/AutoPtr.h>#include "CQLValue.h"#include "CQLIdentifier.h"#include "CQLChainedIdentifier.h"#include "Cql2Dnf.h"// ATTN: TODOs -// optimize// documentationPEGASUS_NAMESPACE_BEGINstruct PropertyNode{ CIMName name; // property name CIMName scope; // class the property is on Boolean wildcard; // true if this property is wildcarded Boolean endpoint; // true if this property is an endpoint // of a chained identifier AutoPtr<PropertyNode> sibling; AutoPtr<PropertyNode> firstChild; PropertyNode() : wildcard(false), endpoint(false), sibling(NULL), firstChild(NULL) {} ~PropertyNode() {}};CQLSelectStatementRep::CQLSelectStatementRep() :SelectStatementRep(), _hasWhereClause(false), _contextApplied(false){ PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep()"); PEG_METHOD_EXIT();}CQLSelectStatementRep::CQLSelectStatementRep(String& inQlang, String& inQuery, QueryContext& inCtx) :SelectStatementRep(inQlang, inQuery, inCtx), _hasWhereClause(false), _contextApplied(false){ PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep(inQlang,inQuery,inCtx)"); PEG_METHOD_EXIT();}CQLSelectStatementRep::CQLSelectStatementRep(String& inQlang, String& inQuery) :SelectStatementRep(inQlang, inQuery), _hasWhereClause(false), _contextApplied(false){ PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep(inQlang,inQuery)"); PEG_METHOD_EXIT();}CQLSelectStatementRep::CQLSelectStatementRep(const CQLSelectStatementRep& rep) :SelectStatementRep(rep), _selectIdentifiers(rep._selectIdentifiers), _hasWhereClause(rep._hasWhereClause), _predicate(rep._predicate), _contextApplied(rep._contextApplied){ PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep(rep)"); PEG_METHOD_EXIT();}CQLSelectStatementRep::~CQLSelectStatementRep(){ PEG_METHOD_ENTER (TRC_CQL, "~CQLSelectStatementRep()"); PEG_METHOD_EXIT();}CQLSelectStatementRep& CQLSelectStatementRep::operator=(const CQLSelectStatementRep& rhs){ PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::operator="); if (this == &rhs) { PEG_METHOD_EXIT(); return *this; } SelectStatementRep::operator=(rhs); _selectIdentifiers = rhs._selectIdentifiers; _predicate = rhs._predicate; _contextApplied = rhs._contextApplied; _hasWhereClause = rhs._hasWhereClause; PEG_METHOD_EXIT(); return *this;}Boolean CQLSelectStatementRep::evaluate(const CIMInstance& inCI){ PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::evaluate"); if(_ctx == NULL) { PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"QC not set"); PEG_METHOD_EXIT(); MessageLoaderParms parms("CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL", "Trying to process a query with a NULL Query Context."); throw CQLRuntimeException(parms); } // Apply to class contexts to the identifiers. // This will check for a well-formed statement. if (!_contextApplied) applyContext(); // Make sure the type of instance passed in is the FROM class, // or a subclass of the FROM class. if (!isFromChild(inCI.getClassName())) { PEG_METHOD_EXIT(); return false; } if (!hasWhereClause()) { PEG_METHOD_EXIT(); return true; } else { try { PEG_METHOD_EXIT(); return _predicate.evaluate(inCI, *_ctx); } catch (CQLNullContagionException& ) { // The null contagion rule. PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"null contagion"); PEG_METHOD_EXIT(); return false; } } PEGASUS_UNREACHABLE( PEGASUS_ASSERT(false); ) PEGASUS_UNREACHABLE( PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"should not get here in evaluate"); ) PEGASUS_UNREACHABLE( return true; ) //should never get here}void CQLSelectStatementRep::applyProjection(CIMInstance& inCI, Boolean allowMissing){ PEG_METHOD_ENTER (TRC_CQL, "CQLSelectStatementRep::applyProjection(inCI)"); if(_ctx == NULL) { PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"QC not set"); PEG_METHOD_EXIT(); MessageLoaderParms parms("CQL.CQLSelectStatementRep.QUERY_CONTEXT_IS_NULL", "Trying to process a query with a NULL Query Context."); throw CQLRuntimeException(parms); } // Apply to class contexts to the identifiers. // This will check for a well-formed statement. if (!_contextApplied) applyContext(); // // Build a tree to represent the projected properties from the select list // of chained identifiers. This is needed because embedded instances below // the FROM class form a tree structure when projected. // // The design of the tree is to gather all the required properties for // an instance at a node as child nodes. The root node // of the tree represents the instance passed in to this function. Below the // root there can be nodes that are required embedded instance properties. // The child nodes of these embedded instance nodes represent the required // properties on the embedded instance (which may themselves be embedded instances). // // Each node has a name, which is in 2 parts -- the property name and the // scope (ie. the class the property is on). This allows the scoping // operator to be handled correctly, so that the parent instance can be // checked to see if it is the right class to provide the property. // Note that the scoping is a base class; ie. the parent instance of a node // may be a subclass of the scope. // // Set up the root node of the tree. This represents the instance // passed in. AutoPtr<PropertyNode> rootNode(new PropertyNode); Array<QueryIdentifier> fromList = _ctx->getFromList(); rootNode->name = fromList[0].getName(); // not doing joins rootNode->scope = fromList[0].getName(); // not used on root, just to fill in the var rootNode->wildcard = false; // Build the tree below the root. for (Uint32 i = 0; i < _selectIdentifiers.size(); i++) { PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"select chained id = " + _selectIdentifiers[i].toString()); // Get the chain elements Array<CQLIdentifier> ids = _selectIdentifiers[i].getSubIdentifiers(); PEGASUS_ASSERT(ids.size() > 1); PropertyNode * curNode = rootNode.get(); PropertyNode * curChild = curNode->firstChild.get(); // Loop through the identifiers in the chain. // NOTE: this starts at the position *after* the FROM class // So, the loop index is always one position after the current node, // ie. it will become a child node of the current node. for (Uint32 j = 1; j < ids.size(); j++) { PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"curNode = " + curNode->name.getString()); PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"id = " + ids[j].toString()); // If the child is wildcarded, then every property exposed by the // class of the instance at the current node is required. // Mark the current node as wildcarded. if (ids[j].isWildcard()) { PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"id is wildcard"); curNode->wildcard = true; break; } // Determine if this identifier is already a child node of // the current node. Boolean found = false; while (curChild != NULL && !found) { // The scoping class is either the scope of the identifier // or the FROM class if the identifier is not scoped. String scope = fromList[0].getName().getString(); if (ids[j].isScoped()) { scope = ids[j].getScope(); } PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"scope to compare = " + scope); if (curChild->name == ids[j].getName() && String::equalNoCase(curChild->scope.getString(), scope)) { // Name and scope match. The identifier is already child node. PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"id is already a child node"); found = true; } else { curChild = curChild->sibling.get(); } } if (!found) { // The identifier is not already a child node. // Create a node and add it as a child to the current node. PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"new child" + ids[j].getName().getString()); curChild = new PropertyNode; curChild->sibling.reset(curNode->firstChild.release()); curChild->name = ids[j].getName(); curChild->wildcard = false; curChild->endpoint = false; curNode->firstChild.reset(curChild); // safer than using the = operator } // Set the scope for the child node if (ids[j].isScoped()) { // Child node has a scoping class PEGASUS_ASSERT(ids[j].getScope().size() > 0); PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"child set with scoping class: " + ids[j].getScope()); curChild->scope = CIMName(ids[j].getScope()); } else { // Not scoped. The scope is the FROM class. PEGASUS_ASSERT(j == 1); PEGASUS_ASSERT(fromList[0].getName().getString().size() > 0); PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"child set with scoping class: " + fromList[0].getName().getString()); curChild->scope = fromList[0].getName(); } // If the identifier is the last element of the chain, // then mark it as an endpoint if ((ids.size() - 1) == j) { curChild->endpoint = true; } curNode = curChild; curChild = curNode->firstChild.get(); } } // // Do the projection. // Array<CIMName> requiredProps; Boolean allPropsRequired = rootNode->wildcard; // Loop through the children of the root node. // The root node represents the FROM class, // and the child nodes are the required properties on the FROM class. PropertyNode* childNode = rootNode->firstChild.get(); while (childNode != NULL) { PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"project childNode = " + childNode->name.getString()); // Determine if the instance passed in meets the class scoping // rules for the current child node. Boolean filterable = isFilterable(inCI, childNode); // Indicates if the child node is still required after the recursive call. Boolean childRequired = true; // If the instance is filterable, and the child node has children, // or is wildcarded, then the child is assumed to be an embedded instance, // and we need to recurse to apply the projection on the embedded instance. // (the check for embedded instance is done in the recursive call) if (filterable && (childNode->firstChild.get() != NULL || childNode->wildcard)) { // We need to project on an embedded instance property. The steps are to // remove the embedded instance property from the instance passed in, // project on that embedded instance property, and then add the projected // embedded instance property back to the instance passed in. PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"about to recurse: " + childNode->name.getString()); Uint32 index = inCI.findProperty(childNode->name); if (index != PEG_NOT_FOUND) { // The instance passed in has the required embedded instance property. // Note: embedded instance property missing is caught below. // Remove the embedded instance property CIMProperty childProp = inCI.getProperty(index); inCI.removeProperty(index); // Project onto the embedded instance property. // If the last parameter is true, then the childNode // will not remove properties when filtering the embedded instance. // This call returns whether the embedded instance property // should be added to the required property list. childRequired = applyProjection(childNode, childProp, allPropsRequired, allowMissing); inCI.addProperty(childProp); } } // If the instance passed in is filterable, // then add the current child to the list if it is still required. if (filterable && childRequired) { PEG_TRACE_STRING (TRC_CQL, Tracer::LEVEL4,"add req prop: " + childNode->name.getString()); requiredProps.append(childNode->name); } childNode = childNode->sibling.get(); } // Remove the properties that are not in the projection. // This also checks for missing required properties. Boolean preserve = false; filterInstance(inCI, allPropsRequired, fromList[0].getName(), requiredProps, preserve,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -