version 1.1, 2004/09/08 15:54:37
|
version 1.1.2.18, 2004/11/04 18:04:05
|
|
|
|
//%2003//////////////////////////////////////////////////////////////////////// |
|
// |
|
// 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. |
|
// |
|
// 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: |
|
// |
|
//%///////////////////////////////////////////////////////////////////////////// |
|
|
|
#include "CQLChainedIdentifier.h" |
|
#include "CQLChainedIdentifierRep.h" |
|
#include <Pegasus/CQL/CQLFactory.h> |
|
#include <Pegasus/CQL/QueryContext.h> |
|
#include "QueryException.h" |
|
|
|
PEGASUS_NAMESPACE_BEGIN |
|
|
|
CQLChainedIdentifierRep::CQLChainedIdentifierRep(){ |
|
} |
|
|
|
CQLChainedIdentifierRep::CQLChainedIdentifierRep(String inString) |
|
{ |
|
parse(inString); |
|
} |
|
|
|
CQLChainedIdentifierRep::CQLChainedIdentifierRep(const CQLIdentifier &id) |
|
{ |
|
_subIdentifiers.append(id); |
|
} |
|
|
|
CQLChainedIdentifierRep::CQLChainedIdentifierRep(const CQLChainedIdentifierRep* rep){ |
|
_subIdentifiers = rep->_subIdentifiers; |
|
} |
|
|
|
CQLChainedIdentifierRep::~CQLChainedIdentifierRep(){ |
|
|
|
} |
|
|
|
const Array<CQLIdentifier>& CQLChainedIdentifierRep::getSubIdentifiers()const |
|
{ |
|
return _subIdentifiers; |
|
} |
|
|
|
CQLIdentifier CQLChainedIdentifierRep::getLastIdentifier()const{ |
|
if(_subIdentifiers.size() > 0) |
|
return _subIdentifiers[_subIdentifiers.size()-1]; |
|
return CQLIdentifier(); |
|
} |
|
|
|
String CQLChainedIdentifierRep::toString()const{ |
|
String s; |
|
for(Uint32 i = 0; i < _subIdentifiers.size(); i++){ |
|
s.append(_subIdentifiers[i].toString()); |
|
if(i < _subIdentifiers.size() - 1) |
|
s.append("."); |
|
} |
|
return s; |
|
} |
|
|
|
void CQLChainedIdentifierRep::append(const CQLIdentifier & id){ |
|
_subIdentifiers.append(id); |
|
} |
|
|
|
Boolean CQLChainedIdentifierRep::isSubChain(const CQLChainedIdentifier & chain)const{ |
|
Array<CQLIdentifier> ids = chain.getSubIdentifiers(); |
|
for(Uint32 i = 0; i < ids.size(); i++){ |
|
if(ids[i] != _subIdentifiers[i].getName()) |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
CQLIdentifier CQLChainedIdentifierRep::operator[](Uint32 index)const |
|
{ |
|
return CQLIdentifier(_subIdentifiers[index]); |
|
} |
|
|
|
CQLChainedIdentifierRep& CQLChainedIdentifierRep::operator=(const CQLChainedIdentifierRep& rhs){ |
|
if(&rhs != this){ |
|
_subIdentifiers = rhs._subIdentifiers; |
|
} |
|
return *this; |
|
} |
|
|
|
Uint32 CQLChainedIdentifierRep::size()const{ |
|
return _subIdentifiers.size(); |
|
} |
|
|
|
Boolean CQLChainedIdentifierRep::prepend(const CQLIdentifier & id){ |
|
/* |
|
Compare id against the first element in _subIdentifiers, |
|
if not an exact match, then prepend. This is used to fully |
|
qualify the chained identifier. |
|
*/ |
|
if(id != _subIdentifiers[0]){ |
|
_subIdentifiers.prepend(id); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
void CQLChainedIdentifierRep::applyContext(QueryContext& inContext) |
|
{ |
|
if (_subIdentifiers.size() == 0) |
|
return; |
|
|
|
// Chained identifiers that are standalone symbolic constants |
|
// should have had the context applied already. If this method |
|
// is called and this is still a standalone symbolic constant, |
|
// then that is an error. |
|
if (_subIdentifiers.size() == 1 && |
|
_subIdentifiers[0].getName().getString().size() == 0 && |
|
_subIdentifiers[0].isSymbolicConstant()) |
|
{ |
|
throw CQLValidationException( |
|
MessageLoaderParms(String("CQL.CQLChainedIdentifier.STAND_ALONE_SYMBOLIC_CONSTANT"), |
|
String("The stand alone chained identifier should have had the context applied already.")) |
|
); |
|
} |
|
|
|
CQLIdentifier firstId = _subIdentifiers[0]; |
|
|
|
// Process if the first identifier has some contents. |
|
if ((firstId.getName().getString().size() != 0) || firstId.isWildcard()) |
|
{ |
|
Array<CQLIdentifier> fromList = inContext.getFromList(); |
|
|
|
if (firstId.isWildcard()) |
|
{ |
|
// First chain element is wildcarded. |
|
// Prepend the FROM class. |
|
_subIdentifiers.prepend(fromList[0]); |
|
} |
|
else |
|
{ |
|
// Not a wildcard. |
|
if (firstId.isScoped()) |
|
{ |
|
// The first identifier is a scoped property or a |
|
// scoped symbolic constant. |
|
// Prepend the FROM class. |
|
// Example: SELECT * FROM F WHERE someprop = X::p#'OK' |
|
_subIdentifiers.prepend(fromList[0]); |
|
} |
|
else |
|
{ |
|
// The first identifier is not a scoped property or a scoped |
|
// symbolic constant. |
|
|
|
// Determine if the first identifier's name is in the FROM list. |
|
String classContext = firstId.getName().getString(); |
|
CQLIdentifier matchedId = inContext.findClass(classContext); |
|
if (matchedId.getName().getString().size() == 0) |
|
{ |
|
// Could not find the firstId in the FROM list. |
|
// Assume the firstId is a property on the FROM class. |
|
// Prepend the FROM class, except in the cases described below. |
|
// |
|
// NOTE: |
|
// We need special handling for symbolic constants, because there are cases |
|
// where the first id is a class that is not the FROM class. |
|
// Refer to section 5.4.3 of the CQL spec. |
|
// |
|
// Examples: |
|
// SELECT * FROM F WHERE F.someprop = prop#'OK' |
|
// Prepend the FROM class because symbolic constants can only |
|
// apply to properties, and properties in the first position |
|
// are assumed to be on the FROM class. |
|
// |
|
// SELECT * FROM F WHERE F.someprop = ClassNotInFromList.prop#'OK' |
|
// We don't want to prepend the FROM class to ClassNotInFromList |
|
// in this case. But we need to get the FROM class from the schema |
|
// to make sure ClassNotInFromList is not a property on the FROM class. |
|
// |
|
// SELECT * FROM F WHERE F.someprop = embeddedObjectOnF.X::p#'OK' |
|
// In this case embeddedObjectOnF is an embedded object property |
|
// on the FROM class. We want to prepend the FROM class. But |
|
// we need to get FROM class from the schema first to make sure. |
|
// |
|
// SELECT * FROM F WHERE F.someprop = embeddedObjectOnF.X::p |
|
// In this case embeddedObjectOnF is an embedded object property |
|
// on the FROM class. We want to prepend the FROM class. Since |
|
// the last id is not a symbolic constant we can prepend without |
|
// getting the FROM class from the schema. |
|
// |
|
// Note that standalone symbolic constants, like #'OK' |
|
// are errors when this code is run. |
|
// See above for details. |
|
// |
|
|
|
if (firstId.isSymbolicConstant() || |
|
!getLastIdentifier().isSymbolicConstant()) |
|
{ |
|
// Must be a property on the FROM class. |
|
_subIdentifiers.prepend(fromList[0]); |
|
} |
|
else |
|
{ |
|
// Get the FROM class. |
|
try |
|
{ |
|
CIMClass fromClass = inContext.getClass(fromList[0].getName()); |
|
if (fromClass.findProperty(firstId.getName()) != PEG_NOT_FOUND) |
|
{ |
|
// A property on the FROM class. |
|
_subIdentifiers.prepend(fromList[0]); |
|
} |
|
} |
|
catch (CIMException& ce) |
|
{ |
|
if (ce.getCode() == CIM_ERR_INVALID_CLASS || |
|
ce.getCode() == CIM_ERR_NOT_FOUND) |
|
{ |
|
// ATTN may just want to throw the CIMException rather than |
|
// CQL exception |
|
throw Exception("TEMP MSG - CQLChainId::applyContext - FROM class does not exist"); |
|
throw CQLValidationException( |
|
MessageLoaderParms(String("CQL.CQLChainedIdentifier.FROM_CLASS_DOES_NOT_EXIST"), |
|
String("The FROM class does not exist while applying context.")) |
|
); |
|
} |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// The firstId was found in the FROM list, but it could have been |
|
// an alias |
|
if (!matchedId.getName().equal(firstId.getName())) |
|
{ |
|
// It was an alias. |
|
// Replace the alias with the FROM class |
|
_subIdentifiers[0] = matchedId; |
|
} |
|
else |
|
{ |
|
// It was not an alias. Do nothing. |
|
; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
// Go through and replace any aliases on scoping classes |
|
for (Uint32 i = 0; i < _subIdentifiers.size(); i++) |
|
{ |
|
if (_subIdentifiers[i].isScoped()) |
|
{ |
|
CQLIdentifier match = inContext.findClass(_subIdentifiers[i].getScope()); |
|
if (match.getName().getString().size() != 0) |
|
{ |
|
// The scoping class was either the FROM class, or an alias of the |
|
// FROM class. Replace the scoping class with the FROM class. |
|
_subIdentifiers[i].applyScope(match.getName().getString()); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void CQLChainedIdentifierRep::parse(String & string){ |
|
/* |
|
- parse string on "." |
|
- start from the end of string |
|
- if more than one substring found, |
|
-- store first found string then |
|
-- prepend remaining substrings |
|
*/ |
|
Char16 delim('.'); |
|
Uint32 index; |
|
String range; |
|
|
|
/* remove any array ranges so we dont parse a false . */ |
|
if((index = string.find("[")) != PEG_NOT_FOUND){ |
|
range = string.subString(index); |
|
string.remove(index); |
|
} |
|
|
|
index = string.reverseFind(delim); |
|
if(index == PEG_NOT_FOUND){ |
|
/* append the range we may have removed */ |
|
string.append(range); |
|
_subIdentifiers.append(CQLIdentifier(string)); |
|
}else{ |
|
/* append the range we may have removed */ |
|
String tmp = string.subString(index+1); |
|
tmp.append(range); |
|
_subIdentifiers.append(CQLIdentifier(tmp)); |
|
|
|
while(index != PEG_NOT_FOUND){ |
|
tmp = string.subString(0,index); |
|
index = tmp.reverseFind(delim); |
|
if(index == PEG_NOT_FOUND){ |
|
_subIdentifiers.prepend(CQLIdentifier(tmp)); |
|
} |
|
else{ |
|
_subIdentifiers.prepend(CQLIdentifier(tmp.subString(index+1))); |
|
} |
|
} |
|
} |
|
} |
|
|
|
PEGASUS_NAMESPACE_END |