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