| // @@@ 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 "QueryTreeView.h" |
| #include "ui_QueryTreeView.h" |
| #include "MainWindow.h" |
| #include "QueryData.h" |
| |
| extern MainWindow *mainWindow_; |
| |
| QueryTreeView::QueryTreeView(QWidget * parent): |
| QWidget(parent), ui(new Ui::QueryTreeView) |
| { |
| ui->setupUi(this); |
| QStringList header; |
| header << "SQL Query Tree" << "Cost" << "Operator Cost" << "Rows" << |
| "Expr Type"; |
| QTreeWidgetItem *hdrItem = new QTreeWidgetItem(header); |
| hdrItem->setIcon(0, QIcon(":/file/R_SQLNODE")); |
| hdrItem->setIcon(1, QIcon(":/file/R_SQLNODE")); |
| hdrItem->setIcon(2, QIcon(":/file/R_SQLNODE")); |
| hdrItem->setIcon(3, QIcon(":/file/R_SQLNODE")); |
| hdrItem->setIcon(4, QIcon(":/file/R_SQLNODE")); |
| ui->m_tree->setHeaderItem(hdrItem); |
| ui->m_tree->setSelectionBehavior(QAbstractItemView::SelectRows); |
| ui->m_tree->setContextMenuPolicy(Qt::CustomContextMenu); |
| ui->m_tree->setIconSize(QSize(32, 32)); |
| ui->m_tree->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); |
| ui->m_tree->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); |
| } |
| |
| QueryTreeView::~QueryTreeView() |
| { |
| delete ui; |
| } |
| |
| /* Public Method Begin */ |
| void QueryTreeView::UpdateView() |
| { |
| //------------------------------------------------------------------ |
| // Delete the existing Tree. |
| //------------------------------------------------------------------ |
| Free(); |
| //------------------------------------------------------------------ |
| // Now we do the tree walk to display the tree. |
| //------------------------------------------------------------------ |
| void *tree; |
| void *plan; |
| mainWindow_->m_querydata->GetData(&tree, &plan); |
| DisplayQueryTree(tree, plan, NULL); |
| ui->m_tree->expandAll(); |
| for (int i = 0; i < ui->m_tree->columnCount(); i++) |
| { |
| ui->m_tree->resizeColumnToContents(i); |
| int width = ui->m_tree->columnWidth(i); |
| ui->m_tree->setColumnWidth(i, width + 30); |
| } |
| } |
| |
| /* Public Method End */ |
| |
| /* Private Method Start */ |
| |
| void QueryTreeView::Free(void) |
| { |
| ui->m_tree->clear(); |
| } |
| |
| void QueryTreeView::DisplayQueryTree(void *tree, void *plan, |
| QTreeWidgetItem * parentTreeItem) |
| { |
| ExprNode *qTree = (ExprNode *) tree; |
| |
| CascadesPlan *cPlan = (CascadesPlan *) plan; |
| DFTDETAILS *pDftDetails; |
| |
| if (qTree != NULL) |
| { |
| Int32 bitmapIndex; |
| NAString nodeText; |
| |
| GetOperatorImageText(qTree, bitmapIndex, nodeText); |
| |
| QString nodeTextData = QString(QLatin1String(nodeText.data())); |
| QStringList rowValues; |
| rowValues.append(nodeTextData); |
| QTreeWidgetItem *treeItem; |
| treeItem = new QTreeWidgetItem(rowValues); |
| treeItem->setIcon(0, QIcon(":/file/Resource/Main/Tdbnodes.bmp")); |
| |
| if (parentTreeItem == NULL) |
| { |
| ui->m_tree->addTopLevelItem(treeItem); |
| } |
| else |
| { |
| parentTreeItem->addChild(treeItem); |
| } |
| |
| pDftDetails = new DFTDETAILS; |
| pDftDetails->currNode = qTree; |
| pDftDetails->currPlan = cPlan; |
| QVariant itemData = qVariantFromValue(pDftDetails); |
| treeItem->setData(0, Qt::UserRole, itemData); |
| //set column alignment for each row |
| treeItem->setTextAlignment(1, Qt::AlignRight | Qt::AlignVCenter); |
| treeItem->setTextAlignment(2, Qt::AlignRight | Qt::AlignVCenter); |
| treeItem->setTextAlignment(3, Qt::AlignRight | Qt::AlignVCenter); |
| |
| if (nodeTextData.compare(QString("NULL"))) |
| { |
| FillExprType(qTree, cPlan, treeItem); |
| FillRowCost(qTree, cPlan, treeItem); |
| } |
| |
| for (Int32 i = qTree->getArity() - 1; i >= 0; i--) |
| { |
| if (cPlan == NULL) |
| { |
| RelExpr *relExpr = (RelExpr *) qTree; |
| if ((relExpr->child(i)).getMode() == ExprGroupId::MEMOIZED) |
| { |
| // display a MEMO group as a leaf op |
| CutOp *l =::new CutOp(99, CmpCommon::statementHeap()); |
| l->setGroupId((relExpr->child(i)).getGroupId()); |
| DisplayQueryTree(l, NULL, treeItem); |
| } |
| else |
| { |
| DisplayQueryTree(qTree->getChild(i), NULL, treeItem); |
| } |
| } |
| else |
| { |
| const CascadesPlan *childPlan; |
| if (cPlan->getContextForChild(i) == NULL) |
| { |
| childPlan = NULL; |
| } |
| else |
| { |
| childPlan = cPlan->getSolutionForChild(i); |
| } |
| |
| if (childPlan != NULL) |
| { |
| DisplayQueryTree(childPlan->getPhysicalExpr(), |
| (void *)childPlan, treeItem); |
| } |
| else |
| { |
| DisplayQueryTree(::new ConstValue(), (void *)childPlan, |
| treeItem); |
| } |
| } // if (cPlan == NULL) |
| } // for loop |
| } //qTree != NULL |
| } |
| |
| void QueryTreeView::GetOperatorImageText(void *tree, Int32 & bitmapIndex, |
| NAString & nodeText) |
| { |
| ExprNode *qTree = (ExprNode *) tree; |
| OperatorTypeEnum opType = qTree->getOperatorType(); |
| switch (opType) |
| { |
| case REL_ROOT: |
| bitmapIndex = IDX_ROOT; |
| nodeText = qTree->getText(); |
| break; |
| case REL_JOIN: |
| bitmapIndex = IDX_JOIN; |
| nodeText = qTree->getText(); |
| break; |
| case REL_SCAN: |
| bitmapIndex = IDX_SCAN; |
| nodeText = qTree->getText(); |
| break; |
| default: |
| bitmapIndex = IDX_GENERIC; |
| nodeText = qTree->getText(); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| // This member function fills in the Group Attribute |
| // information for the list view. |
| //--------------------------------------------------------------- |
| void QueryTreeView::FillGroupAttribs(void *tree, void *plan, |
| QTreeWidgetItem * treeItem) |
| { |
| /* Terry: To be restored |
| GroupAttributes *ga = NULL; |
| QString labelString; |
| |
| ExprNode* qTree = (ExprNode*) tree; |
| CascadesPlan* qPlan = (CascadesPlan*) plan; |
| |
| ga = qTree->castToRelExpr()->getGroupAttr(); |
| |
| if (ga!=NULL) { |
| Lng32 groupId = (Lng32) qTree->castToRelExpr()->getGroupId(); |
| if (groupId == NULL_COLL_INDEX) |
| labelString = QString("in: %d, out: %d").arg(ga->getCharacteristicInputs().entries()).arg(ga->getCharacteristicOutputs().entries()); |
| else |
| labelString = QString("grp: %d, in: %d, out: %d").arg(groupId).arg(ga->getCharacteristicInputs().entries()).arg(ga->getCharacteristicOutputs().entries()); |
| } |
| else |
| { |
| labelString = QString("No Group Properties"); |
| } |
| |
| treeItem->setText(3, labelString); |
| */ |
| } |
| |
| //--------------------------------------------------------------- |
| // This member function fills in the Expression type |
| // information for the list view. |
| //--------------------------------------------------------------- |
| void QueryTreeView::FillExprType(void *tree, void *plan, |
| QTreeWidgetItem * treeItem) |
| { |
| QString labelString; |
| ExprNode *qTree = (ExprNode *) tree; |
| CascadesPlan *qPlan = (CascadesPlan *) plan; |
| |
| if (qTree->castToRelExpr() != NULL) |
| { |
| if (qTree->castToRelExpr()->isPhysical()) |
| { |
| if (qPlan != NULL) |
| { |
| if (qPlan->getPhysicalProperty() != NULL |
| && qPlan->getRollUpCost() != NULL) |
| labelString = QString(" plan"); |
| else |
| labelString = QString(" incomplete plan"); |
| } |
| else |
| { // (qPlan != NULL) |
| if (qTree->castToRelExpr()->getPhysicalProperty() != NULL |
| && qTree->castToRelExpr()->getRollUpCost() != NULL) |
| labelString = QString(" plan"); |
| else |
| labelString = QString(" physical"); |
| } |
| } |
| else |
| { // If not physical |
| labelString = QString(" Logical"); |
| } |
| } |
| else |
| { // (qTree->castToRelExpr() != NULL) |
| labelString = QString(" Unknown"); |
| } |
| treeItem->setText(4, labelString); |
| } |
| |
| //--------------------------------------------------------------- |
| // GSH : This member function fills in the rows and cost |
| // information for the list view. |
| //--------------------------------------------------------------- |
| void QueryTreeView::FillRowCost(void *tree, void *plan, |
| QTreeWidgetItem * treeItem) |
| { |
| GroupAttributes *ga = NULL; |
| double rows; |
| |
| ExprNode *qTree = (ExprNode *) tree; |
| CascadesPlan *qPlan = (CascadesPlan *) plan; |
| |
| float cost = 0.0f; |
| float cost2 = 0.0f; |
| if (qTree->castToRelExpr() != NULL && (ga = qTree->castToRelExpr()->getGroupAttr()) != NULL) |
| { |
| CostScalar numRows = (CostScalar) - 1; |
| if (qPlan != NULL) |
| { |
| ga = qPlan->getPhysicalExpr()->castToRelExpr()->getGroupAttr(); |
| EstLogPropSharedPtr inputLP = |
| qPlan->getContext()->getInputLogProp(); |
| if (ga->existsLogExprForSynthesis()) |
| numRows = |
| ga->outputLogProp(inputLP)->getResultCardinality(); |
| rows = numRows.value(); |
| const Cost *planCost = qPlan->getRollUpCost(); |
| if (planCost) |
| cost = float (planCost->convertToElapsedTime().getValue()); |
| const Cost *operatorCost = qPlan->getOperatorCost(); |
| if (operatorCost) |
| cost2 = |
| float (operatorCost->convertToElapsedTime(). |
| getValue()); |
| } |
| else |
| { |
| rows = numRows.value(); |
| const Cost *planCost = qTree->castToRelExpr()->getRollUpCost(); |
| if (planCost) |
| cost = float (planCost->convertToElapsedTime().getValue()); |
| const Cost *operatorCost = |
| qTree->castToRelExpr()->getOperatorCost(); |
| if (operatorCost) |
| cost2 = |
| float (operatorCost->convertToElapsedTime(). |
| getValue()); |
| //-------------------------------------------------------- |
| } |
| } |
| else |
| { |
| rows = (float)-1; |
| cost = (float)-1; |
| cost2 = (float)-1; |
| } |
| treeItem->setText(1, QString("%1").arg(cost, 0, 'f', 8)); |
| treeItem->setText(2, QString("%1").arg(cost2, 0, 'f', 8)); |
| // -------------------------------------------------------------------- |
| // We want to print "rows" with commas in the appropriate places |
| // --> It's amazing how much work this is! There's got to be some built-in |
| // primitive!!! |
| // -------------------------------------------------------------------- |
| QString string = QString(""); |
| if (rows >= 10000) |
| { |
| UInt32 num_commas = ((UInt32) log10(rows)) / 3; |
| double remains = rows; // don't modify rows |
| // first: print each <int, comma> part |
| for (UInt32 i = num_commas; i > 0; i--) |
| { |
| double p = pow((double)10, (Int32) i * 3); |
| ULng32 head = (ULng32) (remains / p); |
| remains = remains - (head * p); |
| if (i == num_commas) // first thing printed |
| { |
| string.append(QString("%1").arg(head)); |
| //Previous MFC: tmp.Format("%u,", head) ; |
| } |
| else // we may need to print place-holding zero's |
| { |
| if (head < 10) |
| { |
| string.append(QString("00%1").arg(head)); |
| //Previous MFC: tmp.Format("00%u,", head) ; |
| } |
| else if (head < 100) |
| { |
| string.append(QString("0%1").arg(head)); |
| //Previous MFC: tmp.Format("0%u,", head) ; |
| } |
| else |
| { |
| string.append(QString("%1").arg(head)); |
| //Previous MFC: tmp.Format("%u,", head) ; |
| } |
| } |
| } //for |
| // last: print the last part (which is a double) |
| if (remains < 10) |
| { |
| string.append(QString("00%1").arg(remains, 0, 'f', 2)); |
| //Previous MFC: tmp.Format ("00%.2f", remains) ; |
| } |
| else if (remains < 100) |
| { |
| string.append(QString("0%1").arg(remains, 0, 'f', 2)); |
| //Previous MFC: tmp.Format ("0%.2f", remains) ; |
| } |
| else |
| { |
| string.append(QString("%1").arg(remains, 0, 'f', 2)); |
| //Previous MFC: tmp.Format ("%.2f", remains) ; |
| } |
| } |
| else |
| { |
| string = QString("%1").arg(rows, 0, 'f', 2); |
| //Previous MFC: string.Format("%0.2f", rows); |
| } |
| treeItem->setText(3, string); |
| } |
| |
| /* Private Method End */ |
| void QueryTreeView:: |
| on_m_tree_customContextMenuRequested(const QPoint & pos) |
| { |
| QTreeWidgetItem *curItem = ui->m_tree->itemAt(pos); |
| if (curItem == NULL) |
| return; |
| QVariant v = curItem->data(0, Qt::UserRole); |
| DFTDETAILS *pDft = v.value < DFTDETAILS * >(); |
| if (NULL != pDft) |
| { |
| mainWindow_->m_querydata->SetCurrExprAndPlan(pDft->currNode, |
| pDft->currPlan); |
| mainWindow_->popUpContextMenu(QCursor::pos()); |
| } |
| } |