| // ********************************************************************** |
| // @@@ START COPYRIGHT @@@ |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // @@@ END COPYRIGHT @@@ |
| // ********************************************************************** |
| |
| |
| #include "QRDescriptor.h" |
| #include "QRSharedPtr.h" |
| #include "Range.h" |
| // Element names |
| const char QRQueryDescriptor::elemName[] = "Query"; |
| const char QRMVDescriptor::elemName[] = "MV"; |
| const char QRResultDescriptor::elemName[] = "Result"; |
| const char QRPublishDescriptor::elemName[] = "Publish"; |
| const char QRQueryMisc::elemName[] = "Misc"; |
| const char QRJBB::elemName[] = "JBB"; |
| const char QRInfo::elemName[] = "Info"; |
| const char QRHub::elemName[] = "Hub"; |
| const char QRJBBCList::elemName[] = "JBBCList"; |
| const char QRTable::elemName[] = "Table"; |
| const char QRForcedMVs::elemName[] = "ForcedMVs"; |
| template<> const char QRList<QRTable>::elemName[] = "TableList"; |
| const char QROperator::elemName[] = "Operator"; |
| const char QRJoinPred::elemName[] = "JoinPred"; |
| template<> const char QRList<QRJoinPred>::elemName[] = "JoinPredList"; |
| const char QRRangePred::elemName[] = "Range"; |
| template<> const char QRList<QRRangePred>::elemName[] = "RangePredList"; |
| template<> const char QRList<QRExpr>::elemName[] = "ResidualPredList"; |
| const char QROpEQ::elemName[] = "OpEQ"; |
| const char QROpLS::elemName[] = "OpLS"; |
| const char QROpLE::elemName[] = "OpLE"; |
| const char QROpGT::elemName[] = "OpGT"; |
| const char QROpGE::elemName[] = "OpGE"; |
| const char QROpBT::elemName[] = "OpBT"; |
| const char QRNumericVal::elemName[] = "NumericVal"; |
| const char QRStringVal::elemName[] = "StringVal"; |
| const char QRWStringVal::elemName[] = "WStringVal"; |
| const char QRFloatVal::elemName[] = "FloatVal"; |
| const char QRNullVal::elemName[] = "NullVal"; |
| const char QRGroupBy::elemName[] = "GroupBy"; |
| const char QROutput::elemName[] = "Output"; |
| template<> const char QRList<QROutput>::elemName[] = "OutputList"; |
| const char QRExtraHub::elemName[] = "ExtraHub"; |
| const char QRColumn::elemName[] = "Column"; |
| const char QRExpr::elemName[] = "Expr"; |
| const char QRExpr::residElemName[] = "Residual"; // 2 elem names map to QRExpr |
| const char QRBinaryOper::elemName[] = "BinaryOper"; |
| const char QRUnaryOper::elemName[] = "UnaryOper"; |
| const char QRFunction::elemName[] = "Function"; |
| const char QRParameter::elemName[] = "Parameter"; |
| const char QRMVColumn::elemName[] = "MVColumn"; |
| const char QRMVMisc::elemName[] = "Misc"; |
| const char QRJbbResult::elemName[] = "JbbResult"; |
| const char QRJbbSubset::elemName[] = "JbbSubset"; |
| const char QRCandidate::elemName[] = "Candidate"; |
| template<> const char QRList<QRCandidate>::elemName[] = "CandidateList"; |
| const char QRMVName::elemName[] = "MVName"; |
| const char QRVersion::elemName[] = "Version"; |
| const char QRUpdate::elemName[] = "Update"; |
| const char QRInclude::elemName[] = "Include"; |
| const char QRPrimaryGroupBy::elemName[] = "Primary"; |
| const char QRDependentGroupBy::elemName[] = "Dependent"; |
| const char QRMinimalGroupBy::elemName[] = "Minimal"; |
| const char QRKey::elemName[] = "Key"; |
| |
| //////////////////////////////////////////////////// |
| // Member function definitions |
| //////////////////////////////////////////////////// |
| |
| // |
| // AggregateFinderVisitor |
| // |
| |
| Visitor::VisitResult AggregateFinderVisitor::visit(QRElementPtr caller) |
| { |
| if (caller->getElementType() == ET_Function && |
| caller->downCastToQRFunction()->isAnAggregate()) |
| { |
| foundAggregate_ = TRUE; |
| if (findAll_) |
| { |
| aggregatesFound_.insert(caller->getReferencedElement()); |
| return VR_Continue; |
| } |
| return VR_Stop; |
| } |
| |
| return VR_Continue; |
| } |
| |
| Visitor::VisitResult ElementFinderVisitor::visit(QRElementPtr caller) |
| { |
| ElementType callerElemType = caller->getElementType(); |
| for (CollIndex i=0; i<targetTypes_.entries(); i++) |
| { |
| if (callerElemType == targetTypes_[i]) |
| { |
| elementsFound_.insert(useRefedElem_ ? caller->getReferencedElement() |
| : caller); |
| return VR_Continue; |
| } |
| } |
| |
| return VR_Continue; |
| } |
| |
| |
| // |
| // QRElement |
| // |
| |
| const char* const QRElement::ExprResultNames[] = { "Outside", "Provided", "NotProvided" }; |
| |
| QRElement::ExprResult QRElement::encodeResult(const char* resultString) |
| { |
| for (Int32 i=FIRST_EXPR_RESULT; i<INVALID_EXPR_RESULT; i++) |
| { |
| if (!strcmp(resultString, ExprResultNames[i])) |
| return (ExprResult)i; |
| } |
| throw QRDescriptorException("Invalid value for 'result' attribute -- %s", |
| resultString); |
| } |
| |
| Int32 QRElement::cmpQRElement(const void *p1, const void *p2) |
| { |
| QRElementPtr t1 = *((QRElementPtr*)p1); |
| QRElementPtr t2 = *((QRElementPtr*)p2); |
| return t1->getReferencedElement()->getSortName().compareTo(t2->getReferencedElement()->getSortName()); |
| } |
| |
| NAString& QRElement::addEntityRefs(NAString& str, char attrDelim) |
| { |
| const char* specialChars; |
| if (attrDelim == '"') |
| specialChars = "&<\""; |
| else if (attrDelim == '\'') |
| specialChars = "&<'"; |
| else |
| assertLogAndThrow(CAT_SQL_COMP_QR_DESC_GEN, LL_ERROR, |
| FALSE, QRDescriptorException, |
| "addEntityRefs: attribute delimiter must be ' or \""); |
| |
| const char* data = str.data(); |
| if (!strpbrk(data, specialChars)) |
| return str; |
| |
| Int32 inx = str.length() - 1; |
| while (inx >= 0) |
| { |
| switch (data[inx]) |
| { |
| case '&': |
| str.replace(inx, 1, "&"); |
| break; |
| case '<': |
| str.replace(inx, 1, "<"); |
| break; |
| case '"': |
| if (attrDelim == '"') |
| str.replace(inx, 1, """); |
| break; |
| case '\'': |
| if (attrDelim == '\'') |
| str.replace(inx, 1, "'"); |
| break; |
| default: |
| break; |
| } |
| inx--; |
| } |
| return str; |
| } |
| |
| void QRElement::serializeAttrs(XMLString& xml) |
| { |
| if (id_.length() > 0) |
| xml.append("id='").append(id_).append("' "); |
| if (ref_.length() > 0) |
| xml.append("ref='").append(ref_).append("' "); |
| } |
| |
| void QRElement::serializeBoolAttr(const char* attrName, |
| NABoolean attrVal, |
| XMLString& xml) |
| { |
| xml.append(attrName) |
| .append("='") |
| .append(attrVal ? '1' : '0') |
| .append("' "); |
| } |
| |
| void QRElement::deserializeBoolAttr(const char* attrName, |
| const char* attrVal, |
| NABoolean& attr) |
| { |
| if (!strcmp(attrVal, "0")) |
| attr = FALSE; |
| else if (!strcmp(attrVal, "1")) |
| attr = TRUE; |
| else |
| throw QRDescriptorException("Value of %s attribute must be either 0 or 1", |
| attrName); |
| } |
| |
| |
| // |
| // QRElementMapper |
| // |
| |
| XMLElementPtr QRElementMapper::operator()(void *parser, |
| char *elementName, |
| AttributeList atts) |
| { |
| XMLElementPtr elemPtr = NULL; |
| |
| if (!strcmp(elementName, QRQueryDescriptor::elemName)) |
| elemPtr = new (XMLPARSEHEAP) QRQueryDescriptor(atts, ADD_MEMCHECK_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRMVDescriptor::elemName)) |
| elemPtr = new (XMLPARSEHEAP) QRMVDescriptor(atts, ADD_MEMCHECK_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRResultDescriptor::elemName)) |
| elemPtr = new (XMLPARSEHEAP) QRResultDescriptor(atts, ADD_MEMCHECK_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRPublishDescriptor::elemName)) |
| elemPtr = new (XMLPARSEHEAP) QRPublishDescriptor(atts, ADD_MEMCHECK_ARGS(XMLPARSEHEAP)); |
| |
| return elemPtr; |
| } |
| |
| // |
| // QRElementList |
| // |
| |
| QRElementList::QRElementList(ElementType type, XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(type, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| list_(heap) |
| { |
| } |
| |
| QRElementList::~QRElementList() |
| { |
| for (CollIndex i = 0; i < list_.entries(); i++) |
| deletePtr(list_[i]); |
| } |
| |
| void QRElementList::serializeBody(XMLString& xml) |
| { |
| for (CollIndex i = 0; i < list_.entries(); i++) |
| list_[i]->toXML(xml); |
| } |
| |
| NABoolean QRElementList::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| for (CollIndex i = 0; i < list_.entries(); i++) |
| if (list_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRElementList::startItemExprElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementPtr elem = NULL; |
| |
| if (!strcmp(elementName, QRColumn::elemName)) |
| elem = new (XMLPARSEHEAP) QRColumn(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRMVColumn::elemName)) |
| elem = new (XMLPARSEHEAP) QRMVColumn(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRExpr::elemName)) |
| elem = new (XMLPARSEHEAP) QRExpr(this, atts, FALSE, ADD_MEMCHECK_ARGS(XMLPARSEHEAP)); |
| else |
| throw QRDescriptorException("<%s> cannot contain <%s>", |
| getElementName(), elementName); |
| |
| addElement(elem); |
| XMLDocument::setCurrentElement(parser, elem); |
| } |
| |
| |
| // |
| // QRDescriptor |
| // |
| |
| NABoolean QRDescriptor::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| for (CollIndex i=0; i<jbbList_.entries(); i++) |
| if (jbbList_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| // |
| // QRQueryMisc |
| // |
| |
| QRQueryMisc::QRQueryMisc(ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_QueryMisc, NULL, ADD_MEMCHECK_ARGS_PASS(heap)), |
| userID_(heap), |
| mvAge_(heap), |
| optLevel_(heap), |
| rewriteLevel_(MRL_OFF), |
| forcedMVs_(NULL) |
| { |
| } |
| |
| QRQueryMisc::QRQueryMisc(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_QueryMisc, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| userID_(heap), |
| mvAge_(heap), |
| optLevel_(heap), |
| rewriteLevel_(MRL_OFF), |
| forcedMVs_(NULL) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| const char *attrValue; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| attrValue = iter.getValue(); |
| if (!strcmp(attrName, "userID")) |
| userID_ = attrValue; |
| else if (!strcmp(attrName, "MVAge")) |
| mvAge_ = attrValue; |
| else if (!strcmp(attrName, "optLevel")) |
| optLevel_ = attrValue; |
| else if (!strcmp(attrName, "rewriteLevel")) |
| rewriteLevel_ = (MvqrRewriteLevel)atoi(attrValue); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QRQueryMisc::~QRQueryMisc() |
| { |
| deletePtr(forcedMVs_); |
| } |
| |
| NABoolean QRQueryMisc::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (forcedMVs_ && forcedMVs_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRQueryMisc::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRForcedMVs::elemName)) |
| { |
| forcedMVs_ = new (XMLPARSEHEAP) QRForcedMVs(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, forcedMVs_); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| void QRQueryMisc::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (userID_.length() > 0) |
| xml.append("userID='").append(userID_).append("\' "); |
| if (mvAge_.length() > 0) |
| xml.append("MVAge='").append(mvAge_).append("\' "); |
| if (optLevel_.length() > 0) |
| xml.append("optLevel='").append(optLevel_).append("\' "); |
| if (rewriteLevel_ != MRL_OFF) |
| { |
| char buffer[20]; |
| snprintf(buffer, sizeof(buffer), "rewriteLevel='%d' ", (Int32)rewriteLevel_); |
| xml.append(buffer); |
| } |
| } |
| |
| void QRQueryMisc::serializeBody(XMLString& xml) |
| { |
| if (forcedMVs_) |
| forcedMVs_->toXML(xml); |
| } |
| |
| |
| // |
| // QRQueryDescriptor |
| // |
| |
| QRQueryDescriptor::QRQueryDescriptor(AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRDescriptor(ET_QueryDescriptor, ADD_MEMCHECK_ARGS_PASS(heap)), |
| version_(NULL), |
| misc_(NULL), |
| options_(heap) |
| { |
| // Set parent here so we don't have to use 'this' in initializer. |
| setParent(this); |
| |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "options")) |
| options_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QRQueryDescriptor::~QRQueryDescriptor() |
| { |
| deletePtr(version_); |
| deletePtr(misc_); |
| for (CollIndex i = 0; i < jbbList_.entries(); i++) |
| deletePtr(jbbList_[i]); |
| } |
| |
| NABoolean QRQueryDescriptor::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (version_ && version_->treeWalk(visitor)) |
| return TRUE; |
| if (misc_ && misc_->treeWalk(visitor)) |
| return TRUE; |
| for (CollIndex i = 0; i < jbbList_.entries(); i++) |
| if (jbbList_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRQueryDescriptor::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRVersion::elemName)) |
| { |
| version_ = new (XMLPARSEHEAP) QRVersion(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, version_); |
| } |
| else if (!strcmp(elementName, QRQueryMisc::elemName)) |
| { |
| misc_ = new (XMLPARSEHEAP) QRQueryMisc(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, misc_); |
| } |
| else if (!strcmp(elementName, QRJBB::elemName)) |
| { |
| QRJBBPtr jbb = new (XMLPARSEHEAP) QRJBB(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addJBB(jbb); |
| XMLDocument::setCurrentElement(parser, jbb); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| void QRQueryDescriptor::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (options_.length() > 0) |
| xml.append("options='").append(options_).append("\' "); |
| } |
| |
| void QRQueryDescriptor::serializeBody(XMLString& xml) |
| { |
| if (version_) |
| version_->toXML(xml); |
| if (misc_) |
| misc_->toXML(xml); |
| for (CollIndex i = 0; i < jbbList_.entries(); i++) |
| jbbList_[i]->toXML(xml); |
| } |
| |
| |
| // |
| // QRJBB |
| // |
| |
| QRJBB::QRJBB(NumericID idNum, |
| JBB* jbb, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_JBB, NULL, ADD_MEMCHECK_ARGS_PASS(heap)), |
| hub_(new(heap) QRHub(ADD_MEMCHECK_ARGS(heap))), |
| extraHub_(new(heap) QRExtraHub(ADD_MEMCHECK_ARGS(heap))), |
| outputList_(new (heap) QRList<QROutput>(ADD_MEMCHECK_ARGS(heap))), |
| groupBy_(NULL), |
| caNodeId_(0), |
| actualJbbPtr_(jbb), |
| tableArray_(NULL), |
| tableCount_(0), |
| maxTableEntries_(0), |
| gbExpr_(NULL) |
| { |
| setID(idNum); |
| } |
| |
| QRJBB::QRJBB(NumericID idNum, |
| CollIndex nodeId, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_JBB, NULL, ADD_MEMCHECK_ARGS_PASS(heap)), |
| hub_(new(heap) QRHub(ADD_MEMCHECK_ARGS(heap))), |
| extraHub_(new(heap) QRExtraHub(ADD_MEMCHECK_ARGS(heap))), |
| outputList_(new (heap) QRList<QROutput>(ADD_MEMCHECK_ARGS(heap))), |
| groupBy_(NULL), |
| caNodeId_(nodeId), |
| actualJbbPtr_(NULL), |
| tableArray_(NULL), |
| tableCount_(0), |
| maxTableEntries_(0), |
| gbExpr_(NULL) |
| { |
| setID(idNum); |
| } |
| |
| QRJBB::QRJBB(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_JBB, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| hub_(NULL), |
| extraHub_(NULL), |
| outputList_(NULL), |
| groupBy_(NULL), |
| tableArray_(NULL), |
| tableCount_(0), |
| maxTableEntries_(0), |
| gbExpr_(NULL) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QRJBB::~QRJBB() |
| { |
| deletePtr(hub_); |
| deletePtr(extraHub_); |
| deletePtr(outputList_); |
| deletePtr(groupBy_); |
| } |
| |
| NABoolean QRJBB::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (hub_ && hub_->treeWalk(visitor)) |
| return TRUE; |
| if (extraHub_ && extraHub_->treeWalk(visitor)) |
| return TRUE; |
| if (outputList_ && outputList_->treeWalk(visitor)) |
| return TRUE; |
| if (groupBy_ && groupBy_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRJBB::serializeBody(XMLString& xml) |
| { |
| // A JBB that is merely a link to another JBB has no body. |
| if (ref_.length() > 0) |
| return; |
| |
| if (hub_) |
| hub_->toXML(xml); |
| if (extraHub_) |
| extraHub_->toXML(xml); |
| if (outputList_ && !outputList_->isEmpty()) |
| outputList_->toXML(xml); |
| if (groupBy_) |
| groupBy_->toXML(xml); |
| } |
| |
| void QRJBB::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRHub::elemName)) |
| { |
| hub_ = new (XMLPARSEHEAP) QRHub(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, hub_); |
| } |
| else if (!strcmp(elementName, QRExtraHub::elemName)) |
| { |
| extraHub_ = new (XMLPARSEHEAP) QRExtraHub(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, extraHub_); |
| } |
| else if (!strcmp(elementName, QRList<QROutput>::elemName)) |
| { |
| outputList_ = new (XMLPARSEHEAP) QRList<QROutput>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, outputList_); |
| } |
| else if (!strcmp(elementName, QRGroupBy::elemName)) |
| { |
| groupBy_ = new (XMLPARSEHEAP) QRGroupBy(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, groupBy_); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| void QRJBB::createTableArray(CollIndex maxEntries) |
| { |
| assertLogAndThrow1(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| !tableArray_, QRDescriptorException, |
| "tableArray_ already created for jbb %d", getIDNum()); |
| maxTableEntries_ = maxEntries; |
| tableArray_ = new QRTablePtr[maxEntries]; |
| } |
| |
| void QRJBB::addTable(QRTablePtr table) |
| { |
| assertLogAndThrow1(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| tableCount_ < maxTableEntries_, QRDescriptorException, |
| "Found more tables than in jbbc list for jbb %d", getIDNum()); |
| tableArray_[tableCount_++] = table; |
| } |
| |
| |
| // |
| // QRList |
| // |
| |
| template <class T> |
| void QRList<T>::serializeBody(XMLString& xml) |
| { |
| for (CollIndex i = 0; i < list_.entries(); i++) |
| list_[i]->toXML(xml); |
| } |
| |
| template <class T> |
| NABoolean QRList<T>::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| for (CollIndex i = 0; i < list_.entries(); i++) |
| if (list_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| template <class T> |
| void QRList<T>::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, T::elemName)) |
| { |
| PTR_TO_TYPE(T) listElem = new (XMLPARSEHEAP) T(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| list_.insert(listElem); |
| XMLDocument::setCurrentElement(parser, listElem); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| // This template specialization is necessary because QRExpr is associated with two |
| // different elements, and when used as a list, is a list of the secondary one |
| // (<Residual>). So in this specialization, we are looking for residElemName, |
| // instead of elemName as is the case for all other classes. |
| template<> void QRList<QRExpr>::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRExpr::residElemName)) |
| { |
| PTR_TO_TYPE(QRExpr) listElem = |
| new (XMLPARSEHEAP) QRExpr(this, atts, TRUE, ADD_MEMCHECK_ARGS(XMLPARSEHEAP)); |
| list_.insert(listElem); |
| XMLDocument::setCurrentElement(parser, listElem); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| // For some reason, the generic definition does not work, so I used a specific definition for QRRangePred. |
| //template<class T> |
| //void QRList<T>::addItemOrdered(PTR_TO_TYPE(T) item) |
| template<> void QRList<QRRangePred>::addItemOrdered(PTR_TO_TYPE(QRRangePred) item) |
| { |
| CollIndex maxEntries = entries(); |
| if (maxEntries==0) |
| { |
| list_.insert(item); |
| } |
| else |
| { |
| CollIndex pos = 0; |
| const NAString& newID = item->getID(); |
| while (pos<maxEntries && newID > list_[pos]->getID()) |
| pos++; |
| |
| list_.insertAt(pos, item); |
| } |
| } |
| |
| // |
| // QRHub |
| // |
| |
| QRHub::QRHub(ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Hub, NULL, ADD_MEMCHECK_ARGS_PASS(heap)), |
| jbbcList_(new(heap) QRJBBCList(ADD_MEMCHECK_ARGS(heap))), |
| joinPredList_(new(heap) QRList<QRJoinPred>(ADD_MEMCHECK_ARGS(heap))), |
| rangePredList_(new(heap) QRList<QRRangePred>(ADD_MEMCHECK_ARGS(heap))), |
| residualPredList_(new(heap) QRList<QRExpr>(ADD_MEMCHECK_ARGS(heap))) |
| {} |
| |
| QRHub::QRHub(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Hub, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| jbbcList_(NULL), |
| joinPredList_(NULL), |
| rangePredList_(NULL), |
| residualPredList_(NULL) |
| { |
| if (*atts) |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, *atts); |
| } |
| |
| QRHub::~QRHub() |
| { |
| deletePtr(jbbcList_); |
| deletePtr(joinPredList_); |
| deletePtr(rangePredList_); |
| deletePtr(residualPredList_); |
| } |
| |
| void QRHub::serializeBody(XMLString& xml) |
| { |
| if (jbbcList_ && !jbbcList_->isEmpty()) |
| jbbcList_->toXML(xml); |
| if (joinPredList_ && !joinPredList_->isEmpty()) |
| joinPredList_->toXML(xml); |
| if (rangePredList_ && !rangePredList_->isEmpty()) |
| rangePredList_->toXML(xml); |
| if (residualPredList_ && !residualPredList_->isEmpty()) |
| residualPredList_->toXML(xml); |
| } |
| |
| NABoolean QRHub::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (jbbcList_ && !jbbcList_->isEmpty() && jbbcList_->treeWalk(visitor)) |
| return TRUE; |
| if (joinPredList_ && !joinPredList_->isEmpty() && joinPredList_->treeWalk(visitor)) |
| return TRUE; |
| if (rangePredList_ && !rangePredList_->isEmpty() && rangePredList_->treeWalk(visitor)) |
| return TRUE; |
| if (residualPredList_ && !residualPredList_->isEmpty() && residualPredList_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRHub::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRJBBCList::elemName)) |
| { |
| jbbcList_ = new (XMLPARSEHEAP) QRJBBCList(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, jbbcList_); |
| } |
| else if (!strcmp(elementName, QRList<QRJoinPred>::elemName)) |
| { |
| joinPredList_ = new (XMLPARSEHEAP) QRList<QRJoinPred>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, joinPredList_); |
| } |
| else if (!strcmp(elementName, QRList<QRRangePred>::elemName)) |
| { |
| rangePredList_ = new (XMLPARSEHEAP) QRList<QRRangePred>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, rangePredList_); |
| } |
| else if (!strcmp(elementName, QRList<QRExpr>::elemName)) |
| { |
| residualPredList_ = new (XMLPARSEHEAP) QRList<QRExpr>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, residualPredList_); |
| } |
| else |
| { |
| throw QRDescriptorException("<%s> cannot contain <%s>", |
| elemName, elementName); |
| } |
| } |
| |
| // |
| // QRJBBCList |
| // |
| QRJBBCList::QRJBBCList(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElementList(ET_JBBCList, parent, NULL, ADD_MEMCHECK_ARGS_PASS(heap)) |
| { |
| if (*atts) |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, *atts); |
| } |
| |
| void QRJBBCList::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementPtr elem; |
| |
| if (!strcmp(elementName, QRTable::elemName)) |
| elem = new (XMLPARSEHEAP) QRTable(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRJBB::elemName)) |
| elem = new (XMLPARSEHEAP) QRJBB(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QROperator::elemName)) |
| elem = new (XMLPARSEHEAP) QROperator(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else |
| throw QRDescriptorException("<%s> cannot contain <%s>", |
| elemName, elementName); |
| |
| addElement(elem); |
| XMLDocument::setCurrentElement(parser, elem); |
| } |
| |
| void QRJBBCList::setIsKeyCovered() |
| { |
| const ElementPtrList& elemList = getList(); |
| for (CollIndex i=0; i<elemList.entries(); i++) |
| { |
| if (elemList[i]->getElementType() == ET_Table) |
| static_cast<QRTablePtr>(elemList[i])->setIsKeyCovered(TRUE); |
| } |
| } |
| |
| // |
| // QRTable |
| // |
| |
| QRTable::QRTable(ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Table, NULL, ADD_MEMCHECK_ARGS_PASS(heap)), |
| redefTimestamp_(heap), |
| extraHubReason_(heap), |
| isAnMV_(FALSE), |
| tableName_(charData_), |
| isExtraHub_(FALSE), |
| isKeyCovered_(FALSE), |
| numCols_(-1), |
| rangeBits_(heap), |
| residualBits_(heap), |
| hasLOJParent_(FALSE), |
| key_(NULL), |
| correlationName_(heap), |
| joinOrder_(1) |
| { |
| } |
| |
| QRTable::QRTable(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Table, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| redefTimestamp_(heap), |
| extraHubReason_(heap), |
| isAnMV_(false), |
| tableName_(charData_), |
| isExtraHub_(FALSE), |
| isKeyCovered_(FALSE), |
| numCols_(-1), |
| rangeBits_(heap), |
| residualBits_(heap), |
| hasLOJParent_(FALSE), |
| key_(NULL), |
| correlationName_(heap), |
| joinOrder_(1) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| const char *attrVal; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| attrVal = iter.getValue(); |
| if (!strcmp(attrName, "id")) |
| id_ = attrVal; |
| else if (!strcmp(attrName, "ref")) |
| ref_ = attrVal; |
| else if (!strcmp(attrName, "TS")) |
| redefTimestamp_ = attrVal; //@ZX -- probably need to convert to INT64 |
| else if (!strcmp(attrName, "reason")) |
| extraHubReason_ = attrVal; |
| else if (!strcmp(attrName, "isAnMV")) |
| deserializeBoolAttr(attrName, attrVal, isAnMV_); |
| else if (!strcmp(attrName, "isKeyCovered")) |
| deserializeBoolAttr(attrName, attrVal, isKeyCovered_); |
| else if (!strcmp(attrName, "numCols")) |
| setNumCols(atoi(attrVal)); // must call fn, so bitmaps are resized |
| else if (!strcmp(attrName, "rangeBits")) |
| rangeBits_.initFromHexString(attrVal, numCols_); |
| else if (!strcmp(attrName, "residualBits")) |
| residualBits_.initFromHexString(attrVal, numCols_); |
| else if (!strcmp(attrName, "hasLOJParent")) |
| deserializeBoolAttr(attrName, attrVal, hasLOJParent_); |
| else if (!strcmp(attrName, "corr")) |
| correlationName_ = attrVal; |
| else if (!strcmp(attrName, "joinOrder")) |
| joinOrder_ = atoi(attrVal); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QRTable::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (redefTimestamp_.length() > 0) |
| xml.append("TS='").append(redefTimestamp_).append("' "); |
| if (extraHubReason_.length() > 0) |
| xml.append("reason='").append(extraHubReason_).append("' "); |
| if (isAnMV_) // 0 is default |
| xml.append("isAnMV='1' "); |
| if (isKeyCovered_) // 0 is default |
| xml.append("isKeyCovered='1' "); |
| if (numCols_ != -1) |
| { |
| char buffer[20]; |
| snprintf(buffer, sizeof(buffer), "numCols='%d' ", numCols_); |
| xml.append(buffer); |
| } |
| if (hasLOJParent_) // 0 is default |
| xml.append("hasLOJParent='1' "); |
| if (!rangeBits_.isEmpty()) |
| { |
| xml.append("rangeBits='"); |
| rangeBits_.toXML(xml); |
| xml.append("' "); |
| } |
| if (!residualBits_.isEmpty()) |
| { |
| xml.append("residualBits='"); |
| residualBits_.toXML(xml); |
| xml.append("' "); |
| } |
| if (correlationName_ != "") |
| xml.append("corr='").append(correlationName_).append("' "); |
| if (joinOrder_ > 1) |
| { |
| char buffer[20]; |
| snprintf(buffer, sizeof(buffer), "joinOrder='%d' ", joinOrder_); |
| xml.append(buffer); |
| } |
| } |
| |
| void QRTable::serializeBody(XMLString& xml) |
| { |
| QRElement::serializeBody(xml); |
| if (key_) |
| key_->toXML(xml); |
| } |
| |
| void QRTable::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementPtr elem; |
| |
| if (!strcmp(elementName, QRKey::elemName)) |
| { |
| QRKeyPtr key = new (XMLPARSEHEAP) QRKey(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| setKey(key); |
| elem = key; |
| } |
| else |
| throw QRDescriptorException("<%s> cannot contain <%s>", |
| elemName, elementName); |
| |
| XMLDocument::setCurrentElement(parser, elem); |
| } |
| |
| NABoolean QRTable::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (key_ && key_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| // |
| // QRKey |
| // |
| QRKey::QRKey(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElementList(ET_Key, parent, NULL, ADD_MEMCHECK_ARGS_PASS(heap)) |
| { |
| if (*atts) |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, *atts); |
| } |
| |
| void QRKey::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementPtr elem; |
| |
| if (!strcmp(elementName, QRColumn::elemName)) |
| elem = new (XMLPARSEHEAP) QRColumn(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else |
| throw QRDescriptorException("<%s> cannot contain <%s>", |
| elemName, elementName); |
| |
| addElement(elem); |
| XMLDocument::setCurrentElement(parser, elem); |
| } |
| |
| // |
| // QRForcedMVs |
| // |
| |
| QRForcedMVs::~QRForcedMVs() |
| { |
| CollIndex i; |
| for (i = 0; i < tableList_.entries(); i++) |
| deletePtr(tableList_[i]); |
| } |
| |
| NABoolean QRForcedMVs::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| for (CollIndex i = 0; i < tableList_.entries(); i++) |
| if (tableList_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRForcedMVs::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRTablePtr table; |
| if (!strcmp(elementName, QRTable::elemName)) |
| { |
| table = new (XMLPARSEHEAP) QRTable(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, table); |
| addTable(table); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| void QRForcedMVs::serializeBody(XMLString& xml) |
| { |
| CollIndex i; |
| for (i = 0; i < tableList_.entries(); i++) |
| tableList_[i]->toXML(xml); |
| } |
| |
| |
| // |
| // QROperator |
| // |
| |
| QROperator::QROperator(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Operator, parent, ADD_MEMCHECK_ARGS_PASS(heap)) |
| { |
| // Atts of Operator element have not been defined yet |
| } |
| |
| NABoolean QROperator::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| // Add subelements here... |
| |
| return FALSE; |
| } |
| |
| |
| // |
| // QRJoinPred |
| // |
| |
| QRJoinPred::QRJoinPred(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElementList(ET_JoinPred, parent, NULL, ADD_MEMCHECK_ARGS_PASS(heap)), |
| result_(INVALID_EXPR_RESULT) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else if (!strcmp(attrName, "result")) |
| result_ = encodeResult(iter.getValue()); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QRJoinPred::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (result_ != INVALID_EXPR_RESULT) |
| xml.append("result='").append(ExprResultNames[result_]).append( "' "); |
| } |
| |
| void QRJoinPred::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementPtr elem; |
| |
| // A QRJoinPred can also have a QRJoinPred as a child element. |
| if (!strcmp(elementName, QRJoinPred::elemName)) |
| { |
| elem = new (XMLPARSEHEAP) QRJoinPred(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| |
| addElement(elem); |
| XMLDocument::setCurrentElement(parser, elem); |
| } |
| else |
| { |
| QRElementList::startItemExprElement(parser, elementName, atts); |
| } |
| } |
| |
| NABoolean QRJoinPred::isRedundant() const |
| { |
| const ElementPtrList& list = getList(); |
| const NAString& joinPredId = getID(); |
| for (CollIndex i=0; i<list.entries(); i++) |
| { |
| if (joinPredId != list[i]->getRef()) |
| return FALSE; |
| } |
| |
| return TRUE; // all contained eq set members referenced the containing joinpred |
| } |
| |
| QRColumnPtr QRJoinPred::getFirstColumn() |
| { |
| const ElementPtrList& eqList = getEqualityList(); |
| for (CollIndex i=0; i<eqList.entries(); i++) |
| { |
| const QRElementPtr elem = eqList[i]->getReferencedElement(); |
| // Return as soon as we find the first one. |
| if (elem->getElementType() == ET_Column) |
| return elem->downCastToQRColumn(); |
| } |
| |
| // Found no column in equality list, return NULL. |
| return NULL; |
| } |
| |
| |
| // |
| // QRRangePred |
| // |
| |
| QRRangePred::QRRangePred(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_RangePred, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| result_(INVALID_EXPR_RESULT), |
| rangeItem_(NULL), |
| opList_(heap), |
| mustMatch_(FALSE), |
| sqlType_(heap), |
| rangeSpec_(NULL) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else if (!strcmp(attrName, "sqlType")) |
| sqlType_ = iter.getValue(); |
| else if (!strcmp(attrName, "result")) |
| result_ = encodeResult(iter.getValue()); |
| else if (!strcmp(attrName, "mustMatch")) |
| deserializeBoolAttr(attrName, iter.getValue(), mustMatch_); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QRRangePred::~QRRangePred() |
| { |
| deletePtr(rangeItem_); |
| for (CollIndex i = 0; i < opList_.entries(); i++) |
| deletePtr(opList_[i]); |
| |
| // RangeSpec is not a SharedPtr derivative. |
| if (rangeSpec_ != NULL) |
| delete rangeSpec_; |
| } |
| |
| void QRRangePred::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (sqlType_.length() > 0) |
| xml.append("sqlType='").append(sqlType_).append("' "); |
| if (result_ != INVALID_EXPR_RESULT) |
| xml.append("result='").append(ExprResultNames[result_]).append("' "); |
| if (mustMatch_) |
| serializeBoolAttr("mustMatch", mustMatch_, xml); |
| } |
| |
| void QRRangePred::serializeBody(XMLString& xml) |
| { |
| if (rangeItem_) |
| rangeItem_->toXML(xml); |
| if (opList_.entries() == 0) // contains no operators |
| { |
| // Don't add the comment to result descriptor range preds that reference |
| // query preds, because they are always empty. |
| if (result_ == INVALID_EXPR_RESULT || // not in a result descriptor |
| ref_ == "") // or in a constructed range pred |
| { |
| // Add comment to <Range> element explaining that when empty it means |
| // IS NOT NULL is specified or implied, but no other conditions. |
| xml.indent(); |
| xml.append("<!-- empty Range element indicates IS NOT NULL -->"); |
| xml.endLine(); |
| } |
| } |
| else |
| for (CollIndex i = 0; i < opList_.entries(); i++) |
| opList_[i]->toXML(xml); |
| } |
| |
| NABoolean QRRangePred::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (rangeItem_ && rangeItem_->treeWalk(visitor)) |
| return TRUE; |
| for (CollIndex i = 0; i < opList_.entries(); i++) |
| if (opList_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRRangePred::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRRangeOperatorPtr op; |
| |
| if (!strcmp(elementName, QRColumn::elemName)) |
| { |
| setRangeItem(new (XMLPARSEHEAP) QRColumn(CHILD_ELEM_ARGS(XMLPARSEHEAP))); |
| XMLDocument::setCurrentElement(parser, rangeItem_); |
| } |
| else if (!strcmp(elementName, QRMVColumn::elemName)) |
| { |
| setRangeItem(new (XMLPARSEHEAP) QRMVColumn(CHILD_ELEM_ARGS(XMLPARSEHEAP))); |
| XMLDocument::setCurrentElement(parser, rangeItem_); |
| } |
| else if (!strcmp(elementName, QRExpr::elemName)) |
| { |
| setRangeItem(new (XMLPARSEHEAP) QRExpr(this, atts, FALSE, ADD_MEMCHECK_ARGS(XMLPARSEHEAP))); |
| XMLDocument::setCurrentElement(parser, rangeItem_); |
| } |
| else if (!strcmp(elementName, QROpEQ::elemName)) |
| { |
| op = new (XMLPARSEHEAP) QROpEQ(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addOperator(op); |
| XMLDocument::setCurrentElement(parser, op); |
| } |
| else if (!strcmp(elementName, QROpLS::elemName)) |
| { |
| op = new (XMLPARSEHEAP) QROpLS(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addOperator(op); |
| XMLDocument::setCurrentElement(parser, op); |
| } |
| else if (!strcmp(elementName, QROpLE::elemName)) |
| { |
| op = new (XMLPARSEHEAP) QROpLE(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addOperator(op); |
| XMLDocument::setCurrentElement(parser, op); |
| } |
| else if (!strcmp(elementName, QROpGT::elemName)) |
| { |
| op = new (XMLPARSEHEAP) QROpGT(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addOperator(op); |
| XMLDocument::setCurrentElement(parser, op); |
| } |
| else if (!strcmp(elementName, QROpGE::elemName)) |
| { |
| op = new (XMLPARSEHEAP) QROpGE(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addOperator(op); |
| XMLDocument::setCurrentElement(parser, op); |
| } |
| else if (!strcmp(elementName, QROpBT::elemName)) |
| { |
| op = new (XMLPARSEHEAP) QROpBT(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addOperator(op); |
| XMLDocument::setCurrentElement(parser, op); |
| } |
| else |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } // QRRangePred::startElement |
| |
| const RangeSpec* QRRangePred::getRangeSpec(NAMemory* heap) |
| { |
| if (rangeSpec_ == NULL) |
| rangeSpec_ = new (heap) RangeSpec(this, heap); |
| |
| return rangeSpec_; |
| } |
| |
| NABoolean QRRangePred::isSingleValue() |
| { |
| if (opList_.entries() != 1) |
| return FALSE; |
| |
| QRRangeOperatorPtr op=opList_[0]; |
| if (op->getElementType() != ET_OpEQ) |
| return FALSE; |
| |
| QROpEQPtr eqOp = static_cast<QROpEQPtr>(op); |
| return (eqOp->getValueList().entries() == 1 && !eqOp->includesNull()); |
| } |
| |
| Int32 QRRangePred::getSize() |
| { |
| Int32 result = 0; |
| CollIndex maxEntries = opList_.entries(); |
| for (CollIndex i=0; i<maxEntries; i++) |
| result += opList_[i]->getSize(); |
| |
| return result; |
| } |
| |
| // |
| // QROpEQ |
| // |
| |
| QROpEQ::~QROpEQ() |
| { |
| for (CollIndex i = 0; i < valueList_.entries(); i++) |
| deletePtr(valueList_[i]); |
| |
| deletePtr(nullVal_); |
| } |
| |
| void QROpEQ::serializeBody(XMLString& xml) |
| { |
| if (nullVal_) |
| { |
| xml.indent(); |
| xml.append('<').append(nullVal_->getElementName()).append("/>"); |
| xml.endLine(); |
| } |
| |
| for (CollIndex i = 0; i < valueList_.entries(); i++) |
| valueList_[i]->toXML(xml); |
| } |
| |
| NABoolean QROpEQ::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| for (CollIndex i = 0; i < valueList_.entries(); i++) |
| if (valueList_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QROpEQ::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| // Note the early return below when the element is <NullVal> |
| QRScalarValuePtr valElem = NULL; |
| if (!strcmp(elementName, QRNumericVal::elemName)) |
| valElem = new (XMLPARSEHEAP) QRNumericVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRStringVal::elemName)) |
| valElem = new (XMLPARSEHEAP) QRStringVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRWStringVal::elemName)) |
| valElem = new (XMLPARSEHEAP) QRWStringVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRFloatVal::elemName)) |
| valElem = new (XMLPARSEHEAP) QRFloatVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRNullVal::elemName)) |
| { |
| nullVal_ = new (XMLPARSEHEAP) QRNullVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, nullVal_); |
| return; |
| } |
| else |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| if (valElem) |
| { |
| addValue(valElem); |
| XMLDocument::setCurrentElement(parser, valElem); |
| } |
| } |
| |
| void QROpEQ::unparse(NAString& text, const NAString& rangeItem) |
| { |
| CollIndex numValues = valueList_.entries(); |
| if (numValues == 1) |
| { |
| // A single value - use the "<range-item> = <literal>" notation. |
| text.append(rangeItem); |
| text.append(" = "); |
| text.append(valueList_[0]->getSql()); |
| } |
| else if (numValues > 1) |
| { |
| // Multiple values - use the "<range-item> IN ( <literal> [, <literal> ] )" |
| text.append(rangeItem); |
| text.append(" IN ( "); |
| for (CollIndex i=0; i<numValues; i++) |
| { |
| text.append(valueList_[i]->getSql()); |
| if (i<numValues-1) |
| text.append(", "); |
| } |
| text.append(" ) "); |
| } |
| |
| if (nullVal_) |
| { |
| // Add an optional "[OR ] <range-item> IS NULL" |
| if (numValues > 0) |
| text.append(" OR "); |
| |
| text.append(rangeItem); |
| text.append("IS NULL"); |
| } |
| } |
| |
| // |
| // QROpInequality |
| // |
| |
| QROpInequality::QROpInequality(ElementType eType, QRElement *parent, |
| AttributeList atts, const char *elemName, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRRangeOperator(eType, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| value_(NULL), |
| isNormalized_(FALSE) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| const char *attrVal; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| attrVal = iter.getValue(); |
| if (!strcmp(attrName, "isNormalized")) |
| deserializeBoolAttr(attrName, attrVal, isNormalized_); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QROpInequality::~QROpInequality() |
| { |
| deletePtr(value_); |
| } |
| |
| void QROpInequality::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (isNormalized_) |
| serializeBoolAttr("isNormalized", isNormalized_, xml); |
| } |
| |
| void QROpInequality::serializeBody(XMLString& xml) |
| { |
| value_->toXML(xml); |
| } |
| |
| NABoolean QROpInequality::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (value_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QROpInequality::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRNumericVal::elemName)) |
| value_ = new (XMLPARSEHEAP) QRNumericVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRStringVal::elemName)) |
| value_ = new (XMLPARSEHEAP) QRStringVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRWStringVal::elemName)) |
| value_ = new (XMLPARSEHEAP) QRWStringVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRFloatVal::elemName)) |
| value_ = new (XMLPARSEHEAP) QRFloatVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| getElementName(), elementName); |
| XMLDocument::setCurrentElement(parser, value_); |
| } |
| |
| void QROpInequality::unparse(NAString& text, const NAString& rangeItem) |
| { |
| // The text looks like this: "<range-item> <operator-sign> <literal>" |
| text.append(rangeItem); |
| text.append(getOperatorSign()); |
| text.append(value_->getSql()); |
| } |
| |
| // |
| // QROpBT |
| // |
| |
| QROpBT::QROpBT(QRElement *parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRRangeOperator(ET_OpBT, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| valueCount_(0), startValue_(NULL), endValue_(NULL), |
| startIsIncluded_(TRUE), endIsIncluded_(TRUE) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| const char *attrVal; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| attrVal = iter.getValue(); |
| if (!strcmp(attrName, "startIsIncluded")) |
| deserializeBoolAttr(attrName, attrVal, startIsIncluded_); |
| else if (!strcmp(attrName, "endIsIncluded")) |
| deserializeBoolAttr(attrName, attrVal, endIsIncluded_); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QROpBT::~QROpBT() |
| { |
| deletePtr(startValue_); |
| deletePtr(endValue_); |
| } |
| |
| void QROpBT::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| serializeBoolAttr("startIsIncluded", startIsIncluded_, xml); |
| serializeBoolAttr("endIsIncluded", endIsIncluded_, xml); |
| } |
| |
| void QROpBT::serializeBody(XMLString& xml) |
| { |
| if (startValue_) |
| startValue_->toXML(xml); |
| if (endValue_) |
| endValue_->toXML(xml); |
| } |
| |
| NABoolean QROpBT::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (startValue_ && startValue_->treeWalk(visitor)) |
| return TRUE; |
| if (endValue_ && endValue_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QROpBT::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| valueCount_++; |
| if (valueCount_ > 2) |
| throw QRDescriptorException("Only 2 values can be contained in %s", elemName); |
| |
| //QRElementPtr& val = (valueCount_ == 1 ? startValue_ : endValue_); |
| QRScalarValuePtr& val = (valueCount_ == 1 ? startValue_ : endValue_); |
| if (!strcmp(elementName, QRNumericVal::elemName)) |
| val = new (XMLPARSEHEAP) QRNumericVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRStringVal::elemName)) |
| val = new (XMLPARSEHEAP) QRStringVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRWStringVal::elemName)) |
| val = new (XMLPARSEHEAP) QRWStringVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRFloatVal::elemName)) |
| val = new (XMLPARSEHEAP) QRFloatVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| XMLDocument::setCurrentElement(parser, val); |
| } |
| |
| void QROpBT::unparse(NAString& text, const NAString& rangeItem) |
| { |
| if (startIsIncluded_ && endIsIncluded_) |
| { |
| // If both ends are included, use "<range-item> BETWEEN <literal> AND <literal>" |
| text.append(rangeItem); |
| text.append(" BETWEEN "); |
| text.append(startValue_->getSql()); |
| text.append(" AND "); |
| text.append(endValue_->getSql()); |
| } |
| else |
| { |
| // Otherwise use: "(<range-item> <operator> <literal> AND <range-item> <operator> <literal>)" |
| text.append("("); |
| text.append(rangeItem); |
| text.append((startIsIncluded_ ? " >= " : " > ")); |
| text.append(startValue_->getSql()); |
| text.append(" AND "); |
| text.append(rangeItem); |
| text.append((endIsIncluded_ ? " <= " : " < ")); |
| text.append(endValue_->getSql()); |
| text.append(")"); |
| } |
| } |
| |
| // |
| // QRScalarValue |
| // |
| |
| QRScalarValue::QRScalarValue(ElementType eType, QRElement *parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRExplicitExpr(eType, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| stringRep_(charData_), |
| sql_(heap) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| if (!strcmp(attrName, "sql")) |
| sql_ = iter.getValue(); |
| } |
| } |
| |
| void QRScalarValue::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (sql_ != "") |
| xml.append("sql=\"").append(addEntityRefs(sql_, '"')).append("\" "); |
| } |
| |
| // |
| // QRNumericVal |
| // |
| |
| QRNumericVal::QRNumericVal(QRElement *parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRScalarValue(ET_NumericVal, parent, atts, ADD_MEMCHECK_ARGS_PASS(heap)), |
| unscaledNumericVal_(0), numericScale_(0), scale_(heap) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "scale")) |
| scale_ = iter.getValue(); |
| } |
| } |
| |
| void QRNumericVal::setValue(const NAString& value) |
| { |
| // synchNumericValue() uses the string representation of the value, so set |
| // that first. |
| setStringRep(value); |
| synchNumericValue(); |
| } |
| |
| void QRNumericVal::setNumericVal(Int64 unscaledVal, Int32 scale) |
| { |
| unscaledNumericVal_ = unscaledVal; |
| numericScale_ = scale; |
| |
| // Keep string representations of unscaled value and scale consistent with |
| // the new value. |
| snprintf(buf, |
| sizeof(buf), |
| "%0*ld", |
| scale + (unscaledVal < 0), // add one for sign if negative |
| unscaledVal); |
| stringRep_ = buf; |
| if (scale > 0) |
| stringRep_.insert(stringRep_.length() - scale, "."); |
| |
| snprintf(buf, sizeof(buf), "%d", scale); |
| scale_ = buf; |
| } |
| |
| void QRNumericVal::synchNumericValue() |
| { |
| // Store the scale and the unscaled numeric value. |
| // @ZX -- This needs sorting out. It uses the scale attribute rather than the |
| // position of the decimal point in the string representation of the |
| // constant. The scale attribute is redundant with the scaled |
| // representation of the value that is the content of QRNumericVal, and |
| // this needs to be resolved. |
| if (strlen(scale_.data()) > 0) |
| sscanf(scale_.data(), "%d", &numericScale_); |
| |
| Int64 fractionalPart = 0; |
| sscanf(stringRep_.data(), |
| PFLL "." PFLL, |
| &unscaledNumericVal_, &fractionalPart); |
| unscaledNumericVal_ *= (Int64)pow(10, numericScale_); |
| unscaledNumericVal_ += fractionalPart; |
| } |
| |
| |
| // |
| // QRStringVal |
| // |
| |
| void QRStringVal::toXML(XMLString& xml, NABoolean dummy1, NABoolean dummy2) |
| { |
| // Put the content (the string value) directly between the start and end tags |
| // with no spaces or newlines added. No whitespace will be stripped from |
| // StringVal's content when deserialized, allowing for leading and trailing |
| // whitespace that is part of the actual string value. |
| XMLElement::toXML(xml, TRUE); |
| } |
| |
| |
| // |
| // QRWStringVal |
| // |
| |
| void QRWStringVal::toXML(XMLString& xml, NABoolean dummy1, NABoolean dummy2) |
| { |
| // Put the content (the string value) directly between the start and end tags |
| // with no spaces or newlines added. |
| XMLElement::toXML(xml, TRUE); |
| } |
| |
| // Restore the actual code point for a Unicode character encoded as a sequence |
| // of 4 hex digits. Get the 4-bit value for each hex digit and shift it into |
| // position, taking endianness into account. |
| NAWchar QRWStringVal::decode_(const char* buf) const |
| { |
| #ifdef NA_LITTLE_ENDIAN |
| const char* low = buf; |
| const char* high = buf+2; |
| #else |
| const char* low = buf+2; |
| const char* high = buf; |
| #endif |
| NAWchar val = (isdigit(*high) ? *high-48 : *high-55) << 12; |
| val += (isdigit(*(high+1)) ? *(high+1)-48 : *(high+1)-55) << 8; |
| val += (isdigit(*low) ? *low-48 : *low-55) << 4; |
| val += (isdigit(*(low+1)) ? *(low+1)-48 : *(low+1)-55); |
| return val; |
| } |
| |
| // XML parsers have a good deal of latitude in how they break up character data |
| // into calls to this function. The problem for us is that it takes a sequence |
| // of 4 characters of input to decode the sequence into a Unicode character. If |
| // our buffer runs out in the middle of a char's representation, we have to hold |
| // on to the initial part, and put it together with the remaining hex digits |
| // for that character in the next call. |
| void QRWStringVal::charData(void *parser, const char *data, Int32 len) |
| { |
| Int32 startOfst = 0; |
| NAWchar wch; |
| // if danglingCharCount_ is nonzero, we're holding a partial representation |
| // from the previous call. |
| if (danglingCharCount_) |
| { |
| // We don't handle the case where the representation of a single char |
| // spans 3 calls to this function. |
| assertLogAndThrow(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| len >= 4-danglingCharCount_, |
| QRDescriptorException, |
| "charData() received buffer that does not complete dangling char"); |
| // Copy the remainder to our local buffer and decode. |
| memcpy(danglingChars_ + danglingCharCount_, |
| data, |
| 4 - danglingCharCount_); |
| wch = decode_(danglingChars_); |
| wideStringRep_.append(&wch, 1); |
| startOfst = (4 - danglingCharCount_); // update starting point in passed buffer |
| } |
| |
| // Decode each 4-byte sequence in the buffer, and append to the wide char |
| // string. |
| for (Int32 i=startOfst; i<len-3; i+=4) |
| { |
| wch = decode_(data+i); |
| wideStringRep_.append(&wch, 1); |
| } |
| |
| // If there are chars left over (max 3), save them in separate buffer for when |
| // we get the rest in the next call. |
| danglingCharCount_ = (len - startOfst) % 4; |
| if (danglingCharCount_) |
| memcpy(danglingChars_, data + len - danglingCharCount_, danglingCharCount_); |
| } |
| |
| // This array maps the value of a byte to the hex digit pair that represents the |
| // same value in hex. |
| static const char* hexArray[] = |
| { |
| "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", |
| "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", |
| "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", |
| "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", |
| "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", |
| "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", |
| "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", |
| "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", |
| "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", |
| "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", |
| "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", |
| "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", |
| "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", |
| "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", |
| "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", |
| "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF", |
| }; |
| |
| // For each of the double-byte characters that make up the wide string value, |
| // encode it in 4 hex digits and append them to the XML document. |
| void QRWStringVal::serializeBody(XMLString& xml) |
| { |
| // chPtr MUST be unsigned, or value when used as an index could be negative. |
| const unsigned char* chPtr = (const unsigned char*)wideStringRep_.data(); |
| size_t wchLen = wideStringRep_.length(); |
| for (size_t i=0; i<wchLen; i++) |
| { |
| xml.append(hexArray[*chPtr++]); |
| xml.append(hexArray[*chPtr++]); |
| } |
| } |
| |
| |
| // |
| // QRGroupBy |
| // |
| |
| QRGroupBy::QRGroupBy(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_GroupBy, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| result_(INVALID_EXPR_RESULT), |
| primary_(NULL), |
| dependent_(NULL), |
| minimal_(NULL), |
| tableList_(NULL) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else if (!strcmp(attrName, "result")) |
| result_ = encodeResult(iter.getValue()); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QRGroupBy::~QRGroupBy() |
| { |
| deletePtr(primary_); |
| deletePtr(dependent_); |
| deletePtr(minimal_); |
| deletePtr(tableList_); |
| } |
| |
| void QRGroupBy::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (result_ != INVALID_EXPR_RESULT) |
| xml.append("result='").append(ExprResultNames[result_]).append("' "); |
| } |
| |
| void QRGroupBy::serializeBody(XMLString& xml) |
| { |
| if (primary_ && !primary_->isEmpty()) |
| primary_->toXML(xml); |
| |
| if (dependent_ && !dependent_->isEmpty()) |
| dependent_->toXML(xml); |
| |
| if (minimal_ && !minimal_->isEmpty()) |
| minimal_->toXML(xml); |
| |
| if (tableList_ && !tableList_->isEmpty()) |
| tableList_->toXML(xml); |
| } |
| |
| NABoolean QRGroupBy::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (primary_ && primary_->treeWalk(visitor)) |
| return TRUE; |
| |
| if (dependent_ && dependent_->treeWalk(visitor)) |
| return TRUE; |
| |
| if (minimal_ && minimal_->treeWalk(visitor)) |
| return TRUE; |
| |
| if (tableList_ && tableList_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRGroupBy::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementPtr elem = NULL; |
| if (!strcmp(elementName, QRPrimaryGroupBy::elemName)) |
| { |
| primary_ = new (XMLPARSEHEAP) QRPrimaryGroupBy(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| elem = primary_; |
| } |
| else if (!strcmp(elementName, QRDependentGroupBy::elemName)) |
| { |
| dependent_ = new (XMLPARSEHEAP) QRDependentGroupBy(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| elem = dependent_; |
| } |
| else if (!strcmp(elementName, QRMinimalGroupBy::elemName)) |
| { |
| minimal_ = new (XMLPARSEHEAP) QRMinimalGroupBy(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| elem = minimal_; |
| } |
| else if (!strcmp(elementName, QRList<QRTable>::elemName)) |
| { |
| tableList_ = new (XMLPARSEHEAP) QRList<QRTable>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| elem = tableList_; |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| |
| XMLDocument::setCurrentElement(parser, elem); |
| } |
| |
| |
| // |
| // QRPrimaryGroupBy |
| // |
| QRPrimaryGroupBy::QRPrimaryGroupBy(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElementList(ET_PrimaryGroupBy, parent, NULL, ADD_MEMCHECK_ARGS_PASS(heap)) |
| { |
| if (*atts) |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, *atts); |
| } |
| |
| void QRPrimaryGroupBy::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementList::startItemExprElement(parser, elementName, atts); |
| } |
| |
| // |
| // QRDependentGroupBy |
| // |
| QRDependentGroupBy::QRDependentGroupBy(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElementList(ET_DependentGroupBy, parent, NULL, ADD_MEMCHECK_ARGS_PASS(heap)) |
| { |
| if (*atts) |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, *atts); |
| } |
| |
| void QRDependentGroupBy::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementList::startItemExprElement(parser, elementName, atts); |
| } |
| |
| // |
| // QRMinimalGroupBy |
| // |
| QRMinimalGroupBy::QRMinimalGroupBy(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElementList(ET_MinimalGroupBy, parent, NULL, ADD_MEMCHECK_ARGS_PASS(heap)) |
| { |
| if (*atts) |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, *atts); |
| } |
| |
| void QRMinimalGroupBy::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementList::startItemExprElement(parser, elementName, atts); |
| } |
| |
| |
| |
| // |
| // QRColumn |
| // |
| |
| QRColumn::QRColumn(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRExplicitExpr(ET_Column, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| tableId_(heap), |
| fqColumnName_(charData_), |
| columnName_(heap), |
| isExtraHub_(FALSE), |
| colIndex_(-1), |
| isNullable_(1), |
| vegrefVid_(0) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| const char *attrValue; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| attrValue = iter.getValue(); |
| if (!strcmp(attrName, "id")) |
| id_ = attrValue; |
| else if (!strcmp(attrName, "ref")) |
| ref_ = attrValue; |
| else if (!strcmp(attrName, "tableId")) |
| tableId_ = attrValue; |
| else if (!strcmp(attrName, "colIndex")) |
| colIndex_ = atoi(attrValue); |
| else if (!strcmp(attrName, "isNullable")) |
| deserializeBoolAttr(attrName, attrValue, isNullable_); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| |
| // Redefined to initialize the non-fully qualified column name. |
| void QRColumn::charData(void *parser, const char *data, Int32 len) |
| { |
| // Call the superclass first to initialize the fully qualified column name. |
| QRElement::charData(parser, data, len); |
| |
| // Extract the col name from the fully qualified version and set it. |
| setColumnName_(); |
| } |
| |
| void QRColumn::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (tableId_.length() > 0) |
| xml.append("tableId='").append(tableId_).append("' "); |
| if (colIndex_ != -1) |
| { |
| char buffer[20]; |
| snprintf(buffer, sizeof(buffer), "colIndex='%d' ", colIndex_); |
| xml.append(buffer); |
| } |
| if (isNullable_ == FALSE) |
| xml.append("isNullable='0' "); |
| } |
| |
| void QRColumn::setColumnName_() |
| { |
| if (fqColumnName_.length() > 0) // QRColumn with ref attr won't include name |
| { |
| // Find the position of the column name after the last dot |
| UInt32 pos = fqColumnName_.last('.')+1; |
| UInt32 length = fqColumnName_.length(); |
| |
| // Set the column name. |
| columnName_ = fqColumnName_(pos, length - pos); |
| } |
| } |
| |
| void QRColumn::unparse(NAString& text, NABoolean useColumnName) |
| { |
| if (!useColumnName) |
| text.append("<col>"); //"%s"; |
| else |
| text.append(getReferencedElement()->getSortName()); |
| } |
| |
| QRColumnPtr QRColumn::getFirstColumn() |
| { |
| if (getReferencedElement() == this) |
| return this; |
| else |
| return getReferencedElement()->getFirstColumn(); |
| } |
| |
| // |
| // QRExpr |
| // |
| |
| QRExpr::QRExpr(XMLElementPtr parent, AttributeList atts, NABoolean isResidual, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Expr, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| exprRoot_(NULL), |
| unparsedTextWithNames_(heap), |
| unparsedTextNoNames_(heap), |
| unparsedTextCharSet_(CharInfo::ISO88591), |
| inputColumns_(heap), |
| isResidual_(isResidual), |
| isExtraHub_(FALSE), |
| result_(INVALID_EXPR_RESULT), |
| info_(NULL) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else if (!strcmp(attrName, "result")) |
| { |
| assertLogAndThrow(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| isResidual_, QRDescriptorException, |
| "'result' attribute specified for non-residual expr."); |
| result_ = encodeResult(iter.getValue()); |
| } |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| getElementName(), //@ZXresid -- virtual fn in ctor |
| attrName); |
| } |
| } |
| |
| QRExpr::~QRExpr() |
| { |
| deletePtr(exprRoot_); |
| inputColumns_.clear(); |
| deletePtr(info_); |
| } |
| |
| void QRExpr::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (result_ != INVALID_EXPR_RESULT) |
| xml.append("result='").append(ExprResultNames[result_]).append("' "); |
| } |
| |
| void QRExpr::serializeBody(XMLString& xml) |
| { |
| if (exprRoot_) |
| exprRoot_->toXML(xml); |
| if (info_) |
| info_->toXML(xml); |
| } |
| |
| NABoolean QRExpr::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (exprRoot_ && exprRoot_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRExpr::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRBinaryOper::elemName)) |
| { |
| exprRoot_ = new (XMLPARSEHEAP) QRBinaryOper(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, exprRoot_); |
| } |
| else if (!strcmp(elementName, QRFunction::elemName)) |
| { |
| exprRoot_ = new (XMLPARSEHEAP) QRFunction(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, exprRoot_); |
| } |
| else if (!strcmp(elementName, QRUnaryOper::elemName)) |
| { |
| exprRoot_ = new (XMLPARSEHEAP) QRUnaryOper(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, exprRoot_); |
| } |
| else if (!strcmp(elementName, QRMVColumn::elemName)) |
| { |
| exprRoot_ = new (XMLPARSEHEAP) QRMVColumn(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, exprRoot_); |
| } |
| else if (!strcmp(elementName, QRInfo::elemName)) |
| { |
| info_ = new (XMLPARSEHEAP) QRInfo(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, info_); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| getElementName(), elementName); |
| } |
| } |
| |
| const NAString& QRExpr::getExprText(NABoolean useColumnName) |
| { |
| NAString& unparsedText = useColumnName ? unparsedTextWithNames_ : unparsedTextNoNames_; |
| |
| if (unparsedText == "") |
| { |
| assertLogAndThrow(CAT_SQL_COMP_QR_COMMON, LL_MVQR_FAIL, |
| exprRoot_, QRDescriptorException, |
| "QRExpr has null exprRoot_ and no unparsed text"); |
| exprRoot_->unparse(unparsedText, useColumnName); |
| } |
| |
| return unparsedText; |
| } |
| |
| const ElementPtrList& QRExpr::getInputColumns(CollHeap* heap, |
| NABoolean useRefedElem) |
| { |
| if (inputColumns_.entries() == 0) |
| { |
| assertLogAndThrow(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| exprRoot_, QRDescriptorException, |
| "QRExpr has null exprRoot_ and no input columns"); |
| exprRoot_->getInputColumns(inputColumns_, heap, useRefedElem); |
| } |
| |
| return inputColumns_; |
| } |
| |
| QRColumnPtr QRExpr::getFirstColumn() |
| { |
| const ElementPtrList& eqList = getInputColumns(NULL); |
| if (eqList.entries() == 0) |
| return NULL; |
| else |
| return eqList[0]->getReferencedElement()->getFirstColumn(); |
| } |
| |
| // |
| // QRExplicitExpr |
| // |
| |
| NABoolean QRExplicitExpr::containsAnAggregate(CollHeap* heap) |
| { |
| // Return cached value if we've done this already. |
| if (containsAnAggregate_ != AGGREGATE_UNKNOWN) |
| return (NABoolean)containsAnAggregate_; |
| |
| AggregateFinderVisitorPtr aggVisitor |
| = new(heap) AggregateFinderVisitor(ADD_MEMCHECK_ARGS(heap)); |
| treeWalk(aggVisitor); |
| NABoolean returnValue = aggVisitor->foundAggregate(); |
| containsAnAggregate_ = (enum AggregateStatus)returnValue; // cache the result |
| deletePtr(aggVisitor); |
| return returnValue; |
| } |
| |
| QRExplicitExprPtr QRExplicitExpr::deepCopyAndSwitch(subExpressionRewriteHash& subExpressions, |
| CollHeap* heap) |
| { |
| const NAString* id = &getID(); |
| if (*id == "") |
| id = &getRef(); |
| |
| if(subExpressions.contains(id)) |
| { |
| const QRExplicitExprPtr mvCol = subExpressions.getFirstValue(id); |
| subExpressions.remove(id); |
| return mvCol; |
| } |
| else |
| { |
| QRExplicitExprPtr dup = deepCopy(subExpressions, heap); |
| dup->setRef(*id); |
| return dup; |
| } |
| } |
| |
| QRExplicitExprPtr QRExplicitExpr::constructSubElement(void *parser, |
| const char *elementName, |
| const char **atts) |
| { |
| QRExplicitExprPtr elem; |
| if (!strcmp(elementName, QRColumn::elemName)) |
| elem = new (XMLPARSEHEAP) QRColumn(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRMVColumn::elemName)) |
| elem = new (XMLPARSEHEAP) QRMVColumn(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRBinaryOper::elemName)) |
| elem = new (XMLPARSEHEAP) QRBinaryOper(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRFunction::elemName)) |
| elem = new (XMLPARSEHEAP) QRFunction(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRUnaryOper::elemName)) |
| elem = new (XMLPARSEHEAP) QRUnaryOper(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRStringVal::elemName)) |
| elem = new (XMLPARSEHEAP) QRStringVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRWStringVal::elemName)) |
| elem = new (XMLPARSEHEAP) QRWStringVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRNumericVal::elemName)) |
| elem = new (XMLPARSEHEAP) QRNumericVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRFloatVal::elemName)) |
| elem = new (XMLPARSEHEAP) QRFloatVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else if (!strcmp(elementName, QRNullVal::elemName)) |
| elem = new (XMLPARSEHEAP) QRNullVal(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| getElementName(), elementName); |
| } |
| |
| return elem; |
| } |
| |
| void QRExplicitExpr::getInputColumns(ElementPtrList& inputList, CollHeap* heap, |
| NABoolean useRefedElem) |
| { |
| NAList<ElementType> elemTypes(heap); |
| elemTypes.insert(ET_Column); |
| elemTypes.insert(ET_MVColumn); |
| ElementFinderVisitorPtr visitor = |
| new(heap) ElementFinderVisitor(elemTypes, useRefedElem, |
| ADD_MEMCHECK_ARGS(heap)); |
| treeWalk(visitor); |
| inputList = visitor->getElementsFound(); |
| deletePtr(visitor); |
| } |
| |
| // |
| // QRBinaryOper |
| // |
| |
| QRBinaryOper::QRBinaryOper(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRExplicitExpr(ET_BinaryOper, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| operator_(heap), |
| firstOperand_(NULL), |
| secondOperand_(NULL) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else if (!strcmp(attrName, "op")) |
| operator_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QRBinaryOper::serializeAttrs(XMLString& xml) |
| { |
| QRExplicitExpr::serializeAttrs(xml); |
| |
| if (operator_.length() > 0) |
| { |
| const char* opText = operator_.data(); |
| xml.append("op='"); |
| if (*opText == '<') |
| { |
| // Use entity reference in place of '<' to avoid illegal attribute. |
| xml.append("<"); |
| opText++; |
| } |
| xml.append(opText).append("' "); |
| } |
| } |
| |
| void QRBinaryOper::serializeBody(XMLString& xml) |
| { |
| if (firstOperand_) |
| firstOperand_->toXML(xml); |
| if (secondOperand_) |
| secondOperand_->toXML(xml); |
| } |
| |
| NABoolean QRBinaryOper::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (firstOperand_ && firstOperand_->treeWalk(visitor)) |
| return TRUE; |
| if (secondOperand_ && secondOperand_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRBinaryOper::startElement(void* parser, const char* elementName, const char** atts) |
| { |
| QRExplicitExprPtr elem = constructSubElement(parser, elementName, atts); |
| if (!firstOperand_) |
| firstOperand_ = elem; |
| else if (!secondOperand_) |
| secondOperand_ = elem; |
| else |
| throw QRDescriptorException("More than two operands given for binary operator " |
| "with id=%s", id_.data()); |
| |
| XMLDocument::setCurrentElement(parser, elem); |
| } |
| |
| |
| // |
| // QRUnaryOper |
| // |
| |
| QRUnaryOper::QRUnaryOper(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRExplicitExpr(ET_UnaryOper, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| operator_(heap), |
| operand_(NULL) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else if (!strcmp(attrName, "op")) |
| operator_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QRUnaryOper::serializeAttrs(XMLString& xml) |
| { |
| QRExplicitExpr::serializeAttrs(xml); |
| |
| if (operator_.length() > 0) |
| xml.append("op='").append(operator_.data()).append("' "); |
| } |
| |
| void QRUnaryOper::serializeBody(XMLString& xml) |
| { |
| if (operand_) |
| operand_->toXML(xml); |
| } |
| |
| NABoolean QRUnaryOper::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (operand_ && operand_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRUnaryOper::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRExplicitExprPtr elem = constructSubElement(parser, elementName, atts); |
| if (!operand_) |
| operand_ = elem; |
| else |
| throw QRDescriptorException("More than one operand given for unary operator " |
| "with id=%s", id_.data()); |
| |
| XMLDocument::setCurrentElement(parser, elem); |
| } |
| |
| // |
| // QRParameter |
| // |
| |
| QRParameter::QRParameter(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Parameter, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| paramName_(heap), paramValue_(heap) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "name")) |
| paramName_ = iter.getValue(); |
| else if (!strcmp(attrName, "value")) |
| paramValue_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QRParameter::serializeAttrs(XMLString& xml) |
| { |
| assertLogAndThrow1(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| paramName_.length() > 0, QRDescriptorException, |
| "'name' attribute not specified for %s element.", elemName); |
| assertLogAndThrow1(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| paramValue_.length() > 0, QRDescriptorException, |
| "'value' attribute not specified for %s element.", elemName); |
| xml.append("name='").append(paramName_).append("\' "); |
| xml.append("value='").append(paramValue_).append("\' "); |
| } |
| |
| // |
| // QRFunction |
| // |
| |
| QRFunction::QRFunction(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRExplicitExpr(ET_Function, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| function_(heap), |
| arguments_(heap), |
| hiddenParams_(heap), |
| aggregateFunc_(AFT_NONE) |
| { |
| XMLAttributeIterator iter(atts); |
| const char* attrName; |
| const char* attrVal; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| attrVal = iter.getValue(); |
| if (!strcmp(attrName, "id")) |
| id_ = attrVal; |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else if (!strcmp(attrName, "op")) |
| function_ = attrVal; |
| else if (!strcmp(attrName, "aggregateFunc")) |
| aggregateFunc_ = (AggregateFunctionType)atoi(iter.getValue()); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| getElementName(), attrName); |
| } |
| } |
| |
| QRFunction::QRFunction(const QRFunction& other, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRExplicitExpr(other, ADD_MEMCHECK_ARGS_PASS(heap)), |
| function_(other.function_, heap), |
| arguments_(heap), |
| hiddenParams_(heap), |
| aggregateFunc_(other.aggregateFunc_) |
| { |
| for (CollIndex i=0; i<other.hiddenParams_.entries(); i++) |
| addHiddenParam(new(heap) QRParameter(*other.hiddenParams_[i])); |
| } |
| |
| QRFunction::~QRFunction() |
| { |
| for (CollIndex i = 0; i < arguments_.entries(); i++) |
| deletePtr(arguments_[i]); |
| |
| for (CollIndex i = 0; i < hiddenParams_.entries(); i++) |
| deletePtr(hiddenParams_[i]); |
| } |
| |
| void QRFunction::serializeAttrs(XMLString& xml) |
| { |
| QRExplicitExpr::serializeAttrs(xml); |
| |
| if (function_.length() > 0) |
| xml.append("op='").append(function_.data()).append("' "); |
| if (aggregateFunc_ != AFT_NONE) // Optional attr, AF_NONE is the default. |
| { |
| char buffer[20]; |
| snprintf(buffer, sizeof(buffer), "aggregateFunc='%d' ", (Int32)aggregateFunc_); |
| xml.append(buffer); |
| } |
| } |
| |
| void QRFunction::serializeBody(XMLString& xml) |
| { |
| for (CollIndex i = 0; i < arguments_.entries(); i++) |
| arguments_[i]->toXML(xml); |
| |
| for (CollIndex i = 0; i < hiddenParams_.entries(); i++) |
| hiddenParams_[i]->toXML(xml, FALSE, TRUE); |
| } |
| |
| NABoolean QRFunction::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| for (CollIndex i = 0; i < arguments_.entries(); i++) |
| if (arguments_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| for (CollIndex i = 0; i < hiddenParams_.entries(); i++) |
| if (hiddenParams_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRFunction::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRParameter::elemName)) |
| { |
| QRParameterPtr param = |
| new (XMLPARSEHEAP) QRParameter(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addHiddenParam(param); |
| XMLDocument::setCurrentElement(parser, param); |
| } |
| else |
| { |
| QRExplicitExprPtr elem = constructSubElement(parser, elementName, atts); |
| addArgument(elem); |
| XMLDocument::setCurrentElement(parser, elem); |
| } |
| } |
| |
| void QRFunction::setAggregateFunc(OperatorTypeEnum itemExprType, NABoolean isDistinct) |
| { |
| if (isDistinct) |
| { |
| // ItemExpr::getText() for distinct aggregate functions returns a text |
| // that includes a ValueID. This breaks matching, so we need to override |
| // the function name. |
| NAString name; |
| switch (itemExprType) |
| { |
| case ITM_COUNT_NONULL: |
| aggregateFunc_ = AFT_COUNT_DISTINCT; |
| name = "count distinct"; |
| break; |
| |
| case ITM_SUM: |
| aggregateFunc_ = AFT_SUM_DISTINCT; |
| name = "sum distinct"; |
| break; |
| |
| default: |
| throw QRDescriptorException("Unsupported distinct aggregate function."); |
| } |
| setFunctionName(name); |
| } |
| else |
| { |
| switch (itemExprType) |
| { |
| case ITM_COUNT_NONULL: |
| aggregateFunc_ = AFT_COUNT; |
| break; |
| |
| case ITM_COUNT: |
| aggregateFunc_ = AFT_COUNTSTAR; |
| break; |
| |
| case ITM_SUM: |
| aggregateFunc_ = AFT_SUM; |
| break; |
| |
| case ITM_MIN: |
| aggregateFunc_ = AFT_MIN; |
| break; |
| |
| case ITM_MAX: |
| aggregateFunc_ = AFT_MAX; |
| break; |
| |
| case ITM_ONE_ROW: |
| aggregateFunc_ = AFT_ONE_ROW; |
| break; |
| |
| case ITM_ONEROW: |
| aggregateFunc_ = AFT_ONEROW; |
| break; |
| |
| case ITM_ONE_TRUE: |
| aggregateFunc_ = AFT_ONE_TRUE; |
| break; |
| |
| case ITM_ANY_TRUE: |
| aggregateFunc_ = AFT_ANY_TRUE; |
| break; |
| |
| // AVG is not listed here because by now it will get translated to SUM/COUNT. |
| // STDDEV/VARIANCE get translated to ScalarVariance(SUM*SUM, SUM, COUNT) |
| default: |
| throw QRDescriptorException("Unsupported aggregate function."); |
| } |
| } |
| } |
| |
| NABoolean QRFunction::isCountStarEquivalent(CollHeap* heap) |
| { |
| // If its a COUNT(*), than its really easy. |
| if (aggregateFunc_ == AFT_COUNTSTAR) |
| return TRUE; |
| // If its not a COUNT, forget it. |
| else if (aggregateFunc_ != AFT_COUNT) |
| return FALSE; |
| |
| // OK, this is a COUNT. |
| // Now check that all the input columns are not nullable. |
| ElementPtrList inputList(heap); |
| getInputColumns(inputList, heap); |
| |
| NABoolean allInputsAreNotNullable = TRUE; |
| for (CollIndex i=0; i<inputList.entries(); i++) |
| { |
| QRElementPtr input = inputList[i]->getReferencedElement(); |
| if (input->getElementType() != ET_Column) |
| { |
| // This is a join pred. Don't bother for now. |
| allInputsAreNotNullable = FALSE; |
| break; |
| } |
| QRColumnPtr inputCol = input->downCastToQRColumn(); |
| if (inputCol->isNullable()) |
| { |
| allInputsAreNotNullable = FALSE; |
| break; |
| } |
| } |
| |
| return allInputsAreNotNullable; |
| } |
| |
| void QRFunction::unparse(NAString& text, NABoolean useColumnName) |
| { |
| if (function_ == "cast") |
| { |
| // Skip Cast functions. |
| arguments_[0]->unparse(text, useColumnName); |
| } |
| else |
| { |
| text.append(function_ + "["); |
| |
| // Do the parameters inside square brackets. |
| for (CollIndex j=0; j<hiddenParams_.entries(); j++) |
| { |
| QRParameterPtr param = hiddenParams_[j]; |
| text.append(param->getName() + "=" + param->getValue() + " "); |
| } |
| |
| // And then the argumants inside parenthesis. |
| text.append("]("); |
| CollIndex maxEntries = arguments_.entries(); |
| for (CollIndex i=0; i<maxEntries; i++) |
| { |
| arguments_[i]->unparse(text, useColumnName); |
| if (i != maxEntries-1) |
| text.append(", "); |
| } |
| text.append(")"); |
| } |
| } |
| |
| // |
| // QRMVColumn |
| // |
| |
| QRMVColumn::QRMVColumn(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRExplicitExpr(ET_MVColumn, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| mv_(heap), |
| mvColName_(charData_), |
| aggForRewrite_(ITM_NOT) // This means not initialized. |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "MV")) |
| mv_ = iter.getValue(); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QRMVColumn::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (mv_.length() > 0) |
| xml.append("MV='").append(mv_).append("' "); |
| } |
| |
| NABoolean QRMVColumn::hasRefTo(CollIndex vid) |
| { |
| NumericID refNum = getRefNum(); |
| char firstChar = getRefFirstChar(); |
| |
| switch (firstChar) |
| { |
| case 'C': |
| return vid == refNum; |
| |
| case 'J': |
| { |
| QRJoinPredPtr joinPred = getReferencedElement()->downCastToQRJoinPred(); |
| const ElementPtrList& eqList = joinPred->getEqualityList(); |
| for (CollIndex i=0; i<eqList.entries(); i++) |
| { |
| if (vid == eqList[i]->getReferencedElement()->getIDNum()) |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| // Default includes ' ', returned by getRefFirstChar() when there is no ref. |
| default: |
| return FALSE; |
| } |
| } |
| |
| |
| // |
| // QROutput |
| // |
| |
| QROutput::QROutput(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElementList(ET_Output, parent, NULL, ADD_MEMCHECK_ARGS_PASS(heap)), |
| name_(heap), |
| result_(INVALID_EXPR_RESULT), |
| colPos_(-1) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| else if (!strcmp(attrName, "name")) |
| name_ = iter.getValue(); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else if (!strcmp(attrName, "result")) |
| result_ = encodeResult(iter.getValue()); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QROutput::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (name_.length() > 0) |
| xml.append("name='").append(name_).append("' "); |
| if (result_ != INVALID_EXPR_RESULT) |
| xml.append("result='").append(ExprResultNames[result_]).append("' "); |
| } |
| |
| void QROutput::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| QRElementList::startItemExprElement(parser, elementName, atts); |
| } |
| |
| |
| // |
| // QRExtraHub |
| // |
| |
| void QRExtraHub::serializeBody(XMLString& xml) |
| { |
| if (tableList_ && !tableList_->isEmpty()) |
| tableList_->toXML(xml); |
| if (joinPredList_ && !joinPredList_->isEmpty()) |
| joinPredList_->toXML(xml); |
| } |
| |
| NABoolean QRExtraHub::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (tableList_ && !tableList_->isEmpty() && tableList_->treeWalk(visitor)) |
| return TRUE; |
| if (joinPredList_ && !joinPredList_->isEmpty() && joinPredList_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRExtraHub::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRList<QRTable>::elemName)) |
| { |
| tableList_ = new (XMLPARSEHEAP) QRList<QRTable>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, tableList_); |
| } |
| else if (!strcmp(elementName, QRList<QRJoinPred>::elemName)) |
| { |
| joinPredList_ = new (XMLPARSEHEAP) QRList<QRJoinPred>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, joinPredList_); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| |
| // |
| // QRMVMisc |
| // |
| |
| QRMVMisc::QRMVMisc(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_MVMisc, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| isolationLevel_(0), // @ZX -- what should default be? |
| isIncremental_(FALSE), |
| isImmediate_(FALSE), |
| isFromQuery_(FALSE), |
| isUMV_(FALSE) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "isolationLevel")) |
| isolationLevel_ = atoi(iter.getValue()); |
| else if (!strcmp(attrName, "isIncremental")) |
| deserializeBoolAttr(attrName, iter.getValue(), isIncremental_); |
| else if (!strcmp(attrName, "isImmediate")) |
| deserializeBoolAttr(attrName, iter.getValue(), isImmediate_); |
| else if (!strcmp(attrName, "isFromQuery")) |
| deserializeBoolAttr(attrName, iter.getValue(), isFromQuery_); |
| else if (!strcmp(attrName, "isUMV")) |
| deserializeBoolAttr(attrName, iter.getValue(), isUMV_); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QRMVMisc::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| // Isolation level matching not implemented. |
| //char buffer[20]; |
| //sprintf(buffer, "isolationLevel='%d' ", isolationLevel_); |
| //xml.append(buffer); |
| |
| serializeBoolAttr("isIncremental", isIncremental_, xml); |
| if (isImmediate_) |
| serializeBoolAttr("isImmediate", isImmediate_, xml); |
| if (isFromQuery_) |
| serializeBoolAttr("isFromQuery", isFromQuery_, xml); |
| if (isUMV_) |
| serializeBoolAttr("isUMV", isUMV_, xml); |
| } |
| |
| // |
| // QRMVDescriptor |
| // |
| |
| QRMVDescriptor::QRMVDescriptor(AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRDescriptor(ET_MVDescriptor, ADD_MEMCHECK_ARGS_PASS(heap)), |
| version_(NULL), |
| table_(NULL), |
| misc_(NULL) //, |
| //jbbList_(heap) |
| { |
| // Set parent here so we don't have to use 'this' in initializer |
| setParent(this); |
| if (*atts) |
| throw QRDescriptorException("<%s> should have no attributes; attribute %s specified", |
| getElementName(), *atts); |
| } |
| |
| QRMVDescriptor::~QRMVDescriptor() |
| { |
| deletePtr(version_); |
| deletePtr(table_); |
| deletePtr(misc_); |
| for (CollIndex i = 0; i < jbbList_.entries(); i++) |
| deletePtr(jbbList_[i]); |
| } |
| |
| void QRMVDescriptor::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| } |
| |
| void QRMVDescriptor::serializeBody(XMLString& xml) |
| { |
| if (version_) |
| version_->toXML(xml); |
| if (table_) |
| table_->toXML(xml); |
| if (misc_) |
| misc_->toXML(xml); |
| |
| for (CollIndex i = 0; i < jbbList_.entries(); i++) |
| jbbList_[i]->toXML(xml); |
| } |
| |
| NABoolean QRMVDescriptor::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (version_ && version_->treeWalk(visitor)) |
| return TRUE; |
| if (table_ && table_->treeWalk(visitor)) |
| return TRUE; |
| if (misc_ && misc_->treeWalk(visitor)) |
| return TRUE; |
| |
| for (CollIndex i = 0; i < jbbList_.entries(); i++) |
| if (jbbList_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRMVDescriptor::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRVersion::elemName)) |
| { |
| version_ = new (XMLPARSEHEAP) QRVersion(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, version_); |
| } |
| else if (!strcmp(elementName, QRTable::elemName)) |
| { |
| table_ = new (XMLPARSEHEAP) QRTable(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, table_); |
| } |
| else if (!strcmp(elementName, QRMVMisc::elemName)) |
| { |
| misc_ = new (XMLPARSEHEAP) QRMVMisc(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, misc_); |
| } |
| else if (!strcmp(elementName, QRJBB::elemName)) |
| { |
| QRJBBPtr jbb = new (XMLPARSEHEAP) QRJBB(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addJBB(jbb); |
| XMLDocument::setCurrentElement(parser, jbb); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| |
| // |
| // QRMVName |
| // |
| |
| QRMVName::QRMVName(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_MVName, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| timestamp_(heap), |
| fqMVName_(charData_) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "id")) |
| id_ = iter.getValue(); |
| else if (!strcmp(attrName, "TS")) |
| timestamp_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QRMVName::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (timestamp_.length() > 0) |
| xml.append("TS='").append(timestamp_).append("\' "); |
| } |
| |
| |
| // |
| // QRCandidate |
| // |
| |
| QRCandidate::QRCandidate(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Candidate, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| isPreferredMatch_(FALSE), |
| isIndirectGroupBy_(FALSE), |
| statsOnly_(FALSE), |
| mvName_(NULL), |
| tableList_(NULL), |
| joinPredList_(NULL), |
| rangePredList_(NULL), |
| residualPredList_(NULL), |
| groupBy_(NULL), |
| outputList_(NULL) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| const char *attrVal; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| attrVal = iter.getValue(); |
| if (!strcmp(attrName, "statsOnly")) |
| deserializeBoolAttr(attrName, attrVal, statsOnly_); |
| else if (!strcmp(attrName, "isPreferredMatch")) |
| deserializeBoolAttr(attrName, attrVal, isPreferredMatch_); |
| else if (!strcmp(attrName, "isIndirectGroupBy")) |
| deserializeBoolAttr(attrName, attrVal, isIndirectGroupBy_); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QRCandidate::~QRCandidate() |
| { |
| deletePtr(mvName_); |
| deletePtr(tableList_); |
| deletePtr(joinPredList_); |
| deletePtr(rangePredList_); |
| deletePtr(residualPredList_); |
| deletePtr(groupBy_); |
| deletePtr(outputList_); |
| } |
| |
| void QRCandidate::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| serializeBoolAttr("isPreferredMatch", isPreferredMatch_, xml); |
| if (isIndirectGroupBy_) |
| serializeBoolAttr("isIndirectGroupBy", isIndirectGroupBy_, xml); |
| serializeBoolAttr("statsOnly", statsOnly_, xml); |
| } |
| |
| void QRCandidate::serializeBody(XMLString& xml) |
| { |
| if (mvName_) |
| mvName_->toXML(xml); |
| if (tableList_ && !tableList_->isEmpty()) |
| tableList_->toXML(xml); |
| if (joinPredList_ && !joinPredList_->isEmpty()) |
| joinPredList_->toXML(xml); |
| if (rangePredList_ && !rangePredList_->isEmpty()) |
| rangePredList_->toXML(xml); |
| if (residualPredList_ && !residualPredList_->isEmpty()) |
| residualPredList_->toXML(xml); |
| if (groupBy_) |
| groupBy_->toXML(xml); |
| if (outputList_ && !outputList_->isEmpty()) |
| outputList_->toXML(xml); |
| } |
| |
| NABoolean QRCandidate::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (mvName_ && mvName_->treeWalk(visitor)) |
| return TRUE; |
| if (tableList_ && !tableList_->isEmpty() && tableList_->treeWalk(visitor)) |
| return TRUE; |
| if (joinPredList_ && !joinPredList_->isEmpty() && joinPredList_->treeWalk(visitor)) |
| return TRUE; |
| if (rangePredList_ && !rangePredList_->isEmpty() && rangePredList_->treeWalk(visitor)) |
| return TRUE; |
| if (residualPredList_ && !residualPredList_->isEmpty() && residualPredList_->treeWalk(visitor)) |
| return TRUE; |
| if (groupBy_ && groupBy_->treeWalk(visitor)) |
| return TRUE; |
| if (outputList_ && !outputList_->isEmpty() && outputList_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRCandidate::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRMVName::elemName)) |
| { |
| mvName_ = new (XMLPARSEHEAP) QRMVName(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, mvName_); |
| } |
| else if (!strcmp(elementName, QRList<QRTable>::elemName)) |
| { |
| tableList_ = new (XMLPARSEHEAP) QRList<QRTable>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, tableList_); |
| } |
| else if (!strcmp(elementName, QRList<QRJoinPred>::elemName)) |
| { |
| joinPredList_ = new (XMLPARSEHEAP) QRList<QRJoinPred>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, joinPredList_); |
| } |
| else if (!strcmp(elementName, QRList<QRRangePred>::elemName)) |
| { |
| rangePredList_ = new (XMLPARSEHEAP) QRList<QRRangePred>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, rangePredList_); |
| } |
| else if (!strcmp(elementName, QRList<QRExpr>::elemName)) |
| { |
| residualPredList_ = new (XMLPARSEHEAP) QRList<QRExpr>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, residualPredList_); |
| } |
| else if (!strcmp(elementName, QRGroupBy::elemName)) |
| { |
| groupBy_ = new (XMLPARSEHEAP) QRGroupBy(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, groupBy_); |
| } |
| else if (!strcmp(elementName, QRList<QROutput>::elemName)) |
| { |
| outputList_ = new (XMLPARSEHEAP) QRList<QROutput>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, outputList_); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } // QRCandidate::startElement |
| |
| |
| // |
| // QRJbbSubset |
| // |
| |
| QRJbbSubset::QRJbbSubset(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_JbbSubset, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| tableList_(NULL), |
| candidateList_(NULL), |
| hasGroupBy_(FALSE) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| const char *attrVal; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| attrVal = iter.getValue(); |
| if (!strcmp(attrName, "hasGroupby")) |
| deserializeBoolAttr(attrName, attrVal, hasGroupBy_); |
| else if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| void QRJbbSubset::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| serializeBoolAttr("hasGroupby", hasGroupBy_, xml); |
| } |
| |
| void QRJbbSubset::serializeBody(XMLString& xml) |
| { |
| if (tableList_ && !tableList_->isEmpty()) |
| tableList_->toXML(xml); |
| if (candidateList_ && !candidateList_->isEmpty()) |
| candidateList_->toXML(xml); |
| } |
| |
| NABoolean QRJbbSubset::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (tableList_ && !tableList_->isEmpty() && tableList_->treeWalk(visitor)) |
| return TRUE; |
| if (candidateList_ && !candidateList_->isEmpty() && candidateList_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRJbbSubset::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRList<QRTable>::elemName)) |
| { |
| tableList_ = new (XMLPARSEHEAP) QRList<QRTable>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, tableList_); |
| } |
| else if (!strcmp(elementName, QRList<QRCandidate>::elemName)) |
| { |
| candidateList_ = new (XMLPARSEHEAP) QRList<QRCandidate>(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, candidateList_); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| |
| // |
| // QRJbbResult |
| // |
| |
| QRJbbResult::QRJbbResult(XMLElementPtr parent, AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_JbbResult, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| jbbSubsets_(heap), |
| infoItems_(heap) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "ref")) |
| ref_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QRJbbResult::~QRJbbResult() |
| { |
| CollIndex i; |
| for (i = 0; i < jbbSubsets_.entries(); i++) |
| deletePtr(jbbSubsets_[i]); |
| for (i = 0; i < infoItems_.entries(); i++) |
| deletePtr(infoItems_[i]); |
| } |
| |
| void QRJbbResult::serializeBody(XMLString& xml) |
| { |
| CollIndex i; |
| for (i = 0; i < jbbSubsets_.entries(); i++) |
| jbbSubsets_[i]->toXML(xml); |
| for (i = 0; i < infoItems_.entries(); i++) |
| infoItems_[i]->toXML(xml); |
| } |
| |
| NABoolean QRJbbResult::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| CollIndex i; |
| for (i = 0; i < jbbSubsets_.entries(); i++) |
| if (jbbSubsets_[i]->treeWalk(visitor)) |
| return TRUE; |
| for (i = 0; i < infoItems_.entries(); i++) |
| if (infoItems_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRJbbResult::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRJbbSubset::elemName)) |
| { |
| QRJbbSubsetPtr jbbSubset = new (XMLPARSEHEAP) QRJbbSubset(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addJbbSubset(jbbSubset); |
| XMLDocument::setCurrentElement(parser, jbbSubset); |
| } |
| else if (!strcmp(elementName, QRInfo::elemName)) |
| { |
| QRInfoPtr info = new (XMLPARSEHEAP) QRInfo(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addInfoItem(info); |
| XMLDocument::setCurrentElement(parser, info); |
| } |
| else |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| |
| |
| // |
| // QRResultDescriptor |
| // |
| |
| QRResultDescriptor::~QRResultDescriptor() |
| { |
| deletePtr(version_); |
| for (CollIndex i = 0; i < jbbResults_.entries(); i++) |
| deletePtr(jbbResults_[i]); |
| } |
| |
| void QRResultDescriptor::serializeBody(XMLString& xml) |
| { |
| if (version_) |
| version_->toXML(xml); |
| for (CollIndex i = 0; i < jbbResults_.entries(); i++) |
| jbbResults_[i]->toXML(xml); |
| } |
| |
| NABoolean QRResultDescriptor::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (version_ && version_->treeWalk(visitor)) |
| return TRUE; |
| for (CollIndex i = 0; i < jbbResults_.entries(); i++) |
| if (jbbResults_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRResultDescriptor::startElement(void *parser, const char *elementName, const char **atts) |
| { |
| if (!strcmp(elementName, QRVersion::elemName)) |
| { |
| version_ = new (XMLPARSEHEAP) QRVersion(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, version_); |
| } |
| else if (!strcmp(elementName, QRJbbResult::elemName)) |
| { |
| QRJbbResultPtr jbbResult = new (XMLPARSEHEAP) QRJbbResult(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addJbbResult(jbbResult); |
| XMLDocument::setCurrentElement(parser, jbbResult); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| |
| // |
| // QRPublishDescriptor |
| // |
| |
| QRPublishDescriptor::QRPublishDescriptor(AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_PublishDescriptor, NULL, ADD_MEMCHECK_ARGS_PASS(heap)), |
| redefTimestamp_(heap), |
| name_(NULL), |
| updateList_(heap), |
| includeFile_(NULL), |
| mvDesc_(NULL), |
| mvDescText_(NULL) |
| { |
| // Set parent here so we don't have to use 'this' in initializer. |
| setParent(this); |
| |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| if (!strcmp(attrName, "TS")) |
| redefTimestamp_ = iter.getValue(); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QRPublishDescriptor::~QRPublishDescriptor() |
| { |
| deletePtr(name_); |
| deletePtr(includeFile_); |
| deletePtr(mvDesc_); |
| |
| if (mvDescText_) |
| delete mvDescText_; |
| |
| for (CollIndex i=0; i<updateList_.entries(); i++) |
| deletePtr(updateList_[i]); |
| } |
| |
| NABoolean QRPublishDescriptor::treeWalk(VisitorPtr visitor) |
| { |
| VISIT_THIS(visitor, this); |
| |
| if (name_ && name_->treeWalk(visitor)) |
| return TRUE; |
| |
| for (CollIndex i=0; i<updateList_.entries(); i++) |
| if (updateList_[i]->treeWalk(visitor)) |
| return TRUE; |
| |
| if (includeFile_ && includeFile_->treeWalk(visitor)) |
| return TRUE; |
| |
| if (mvDesc_ && mvDesc_->treeWalk(visitor)) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void QRPublishDescriptor::startElement(void *parser, |
| const char *elementName, |
| const char **atts) |
| { |
| if (!strcmp(elementName, QRUpdate::elemName)) |
| { |
| QRUpdatePtr update = new (XMLPARSEHEAP) QRUpdate(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| addUpdate(update); |
| XMLDocument::setCurrentElement(parser, update); |
| } |
| else if (!strcmp(elementName, QRMVName::elemName)) |
| { |
| name_ = new (XMLPARSEHEAP) QRMVName(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, name_); |
| } |
| else if (!strcmp(elementName, QRInclude::elemName)) |
| { |
| includeFile_ = new (XMLPARSEHEAP) QRInclude(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, includeFile_); |
| } |
| else if (!strcmp(elementName, QRMVDescriptor::elemName)) |
| { |
| mvDesc_ = new (XMLPARSEHEAP) QRMVDescriptor(CHILD_ELEM_ARGS(XMLPARSEHEAP)); |
| XMLDocument::setCurrentElement(parser, mvDesc_); |
| } |
| else |
| { |
| throw QRDescriptorException("Element %s cannot contain element %s", |
| elemName, elementName); |
| } |
| } |
| |
| void QRPublishDescriptor::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| if (redefTimestamp_.length() > 0) |
| xml.append("TS='").append(redefTimestamp_).append("\' "); |
| } |
| |
| void QRPublishDescriptor::serializeBody(XMLString& xml) |
| { |
| if (name_) |
| name_->toXML(xml); |
| |
| for (CollIndex i=0; i<updateList_.entries(); i++) |
| updateList_[i]->toXML(xml); |
| |
| if (includeFile_) |
| includeFile_->toXML(xml); |
| |
| if (mvDesc_) |
| mvDesc_->toXML(xml); |
| |
| if (mvDescText_) |
| { |
| xml.incrementLevel(); |
| xml.indent(); |
| xml.append(mvDescText_->data()); |
| xml.endLine(); |
| xml.decrementLevel(); |
| } |
| } |
| |
| void QRPublishDescriptor::initialize(ComPublishMVOperationType opType, |
| const NAString* redefTimestamp, |
| NAString* mvDescText, |
| const NAString* mvName, |
| NABoolean hasIgnoreChanges, |
| const NAString* refreshTimestamp, |
| const NAString* newName, |
| NAMemory* heap) |
| { |
| setRedefTimestamp(*redefTimestamp); |
| |
| QRMVNamePtr nameElement = new(heap) QRMVName(ADD_MEMCHECK_ARGS(heap)); |
| nameElement->setMVName(*mvName); |
| setName(nameElement); |
| |
| switch(opType) |
| { |
| case COM_PUBLISH_MV_CREATE_AND_REFRESH: |
| addUpdate(createUpdateForRefresh(refreshTimestamp, heap)); |
| // Fall through to CREATE. |
| case COM_PUBLISH_MV_CREATE: |
| if (hasIgnoreChanges) |
| addUpdate(createUpdateForAlter(hasIgnoreChanges, heap)); |
| setMVText(mvDescText, heap); |
| break; |
| |
| case COM_PUBLISH_MV_RENAME: |
| addUpdate(createUpdateForRename(newName, heap)); |
| break; |
| |
| case COM_PUBLISH_MV_ALTER_IGNORE_CHANGES: |
| addUpdate(createUpdateForAlter(hasIgnoreChanges, heap)); |
| break; |
| |
| case COM_PUBLISH_MV_TOUCH: |
| // Nothing to do here. |
| break; |
| |
| case COM_PUBLISH_MV_DROP: |
| addUpdate(createUpdateForDrop(heap)); |
| break; |
| |
| case COM_PUBLISH_MV_REPUBLISH: |
| setMVText(mvDescText, heap); |
| addUpdate(createUpdateForAlter(hasIgnoreChanges, heap)); |
| addUpdate(createUpdateForRefresh(refreshTimestamp, heap)); |
| break; |
| |
| case COM_PUBLISH_MV_REFRESH: |
| addUpdate(createUpdateForRefresh(refreshTimestamp, heap)); |
| break; |
| |
| case COM_PUBLISH_MV_REFRESH_RECOMPUTE: |
| addUpdate(createUpdateForRecompute(refreshTimestamp, heap)); |
| break; |
| |
| case COM_PUBLISH_MV_UNKNOWN: |
| default: |
| assertLogAndThrow(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| FALSE, QRDescriptorException, |
| "Unhandled MV operation type"); |
| break; |
| } |
| } |
| |
| QRUpdatePtr QRPublishDescriptor::createUpdateForAlter(NABoolean hasIgnoreChanges, NAMemory* heap) |
| { |
| QRUpdatePtr update = new (heap) QRUpdate(QRUpdate::ALTER, ADD_MEMCHECK_ARGS(heap)); |
| update->setIgnoreChanges(hasIgnoreChanges); |
| return update; |
| } |
| |
| QRUpdatePtr QRPublishDescriptor::createUpdateForRefresh(const NAString* refreshTimestamp, NAMemory* heap) |
| { |
| QRUpdatePtr update = new (heap) QRUpdate(QRUpdate::REFRESH, ADD_MEMCHECK_ARGS(heap)); |
| update->setRefreshTimestamp(*refreshTimestamp); |
| return update; |
| } |
| |
| QRUpdatePtr QRPublishDescriptor::createUpdateForRecompute(const NAString* refreshTimestamp, NAMemory* heap) |
| { |
| QRUpdatePtr update = new (heap) QRUpdate(QRUpdate::RECOMPUTE, ADD_MEMCHECK_ARGS(heap)); |
| update->setRefreshTimestamp(*refreshTimestamp); |
| return update; |
| } |
| |
| QRUpdatePtr QRPublishDescriptor::createUpdateForDrop(NAMemory* heap) |
| { |
| QRUpdatePtr update = new (heap) QRUpdate(QRUpdate::DROP, ADD_MEMCHECK_ARGS(heap)); |
| return update; |
| } |
| |
| QRUpdatePtr QRPublishDescriptor::createUpdateForRename(const NAString* newName, NAMemory* heap) |
| { |
| QRUpdatePtr update = new (heap) QRUpdate(QRUpdate::RENAME, ADD_MEMCHECK_ARGS(heap)); |
| update->setNewName(*newName); |
| return update; |
| } |
| |
| // |
| // QRUpdate |
| // |
| |
| // The order of these names must match that of the UpdateType enum. |
| const char* const QRUpdate::UpdateTypeNames_[] = |
| { "Non-Init", "Alter", "Default", "Drop", "Recompute", "Refresh", "Rename" }; |
| |
| QRUpdate::QRUpdate(XMLElementPtr parent, |
| AttributeList atts, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Update, parent, ADD_MEMCHECK_ARGS_PASS(heap)), |
| type_(NON_INIT), |
| timestamp_(heap), |
| hasIgnoreChanges_(FALSE), |
| newName_(charData_), |
| defaultName_(heap), |
| defaultValue_(heap) |
| { |
| XMLAttributeIterator iter(atts); |
| const char *attrName; |
| const char *attrVal; |
| |
| while (iter.hasNext()) |
| { |
| iter.next(); |
| attrName = iter.getName(); |
| attrVal = iter.getValue(); |
| |
| if (!strcmp(attrName, "TS")) // refresh timestamp; only for op=Refresh |
| timestamp_ = attrVal; //@ZX -- probably need to convert to INT64 |
| else if (!strcmp(attrName, "attr")) // default attribute name for op=Default |
| defaultName_ = attrVal; |
| else if (!strcmp(attrName, "value")) // default attribute value for op=Default |
| defaultValue_ = attrVal; |
| else if (!strcmp(attrName, "op")) |
| { |
| if (!strcmp(attrVal, "Refresh")) |
| type_ = REFRESH; |
| else if (!strcmp(attrVal, "Recompute")) |
| type_ = RECOMPUTE; |
| else if (!strcmp(attrVal, "Drop")) |
| type_ = DROP; |
| else if (!strcmp(attrVal, "Alter")) |
| type_ = ALTER; |
| else if (!strcmp(attrVal, "Rename")) |
| type_ = RENAME; |
| else if (!strcmp(attrVal, "Default")) |
| type_ = DEFAULT; |
| else |
| throw QRDescriptorException("Invalid Update type: %s", attrVal); |
| } |
| else if (!strcmp(attrName, "hasIgnoreChanges")) |
| deserializeBoolAttr(attrName, attrVal, hasIgnoreChanges_); |
| else |
| throw QRDescriptorException("Invalid attribute specified for element %s: %s", |
| elemName, attrName); |
| } |
| } |
| |
| QRUpdate::QRUpdate(UpdateType updateType, |
| ADD_MEMCHECK_ARGS_DEF(NAMemory* heap)) |
| : QRElement(ET_Update, NULL, ADD_MEMCHECK_ARGS_PASS(heap)), |
| type_(updateType), |
| timestamp_(heap), |
| hasIgnoreChanges_(FALSE), |
| newName_(charData_) |
| { |
| } |
| |
| void QRUpdate::serializeAttrs(XMLString& xml) |
| { |
| QRElement::serializeAttrs(xml); |
| |
| assertLogAndThrow(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| type_ != NON_INIT, QRDescriptorException, |
| "Op type has not been set for <Update>"); |
| xml.append("op='").append(UpdateTypeNames_[type_]).append("' "); |
| |
| switch (type_) |
| { |
| case ALTER: |
| serializeBoolAttr("hasIgnoreChanges", hasIgnoreChanges_, xml); |
| break; |
| |
| case REFRESH: |
| case RECOMPUTE: |
| xml.append("TS='").append(timestamp_).append("' "); |
| break; |
| |
| case DEFAULT: |
| assertLogAndThrow(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| defaultName_.length() > 0, QRDescriptorException, |
| "Attribute name not available for default operation"); |
| assertLogAndThrow(CAT_SQL_COMP_QR_DESC_GEN, LL_MVQR_FAIL, |
| defaultValue_.length() > 0, QRDescriptorException, |
| "Attribute value not available for default operation"); |
| |
| xml.append("attr='").append(defaultName_).append("' "); |
| xml.append("value='").append(defaultValue_).append( "' "); |
| break; |
| |
| case DROP: |
| // Nothing to do here. |
| break; |
| } |
| } |