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