blob: fc9c1f1398258dc905ce1cc6ad15efd21d6f3703 [file] [log] [blame]
// @@@ 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());
}
}