blob: ee675a3b55e5b286d01e3cfab32c77715e80d0bd [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 @@@
**********************************************************************/
/* -*-C++-*-
**************************************************************************
*
* File: RETDesc.C
* Description: Descriptor for the table derived from a RelExpr
* Created: 6/1/95
* Language: C++
*
*
**************************************************************************
*/
#include "Sqlcomp.h"
#include "AllItemExpr.h"
#include "BindWA.h"
#include "Refresh.h"
#include "MvRefreshBuilder.h"
#include "MVInfo.h"
// ***********************************************************************
// RETDesc::RETDesc()
// ***********************************************************************
RETDesc::RETDesc()
: groupedFlag_(FALSE),
xtnm_(CmpCommon::statementHeap()),
xcnm_(CmpCommon::statementHeap()),
userColumnList_(CmpCommon::statementHeap()),
naTypeForUserColumnList_(CmpCommon::statementHeap()),
systemColumnList_(CmpCommon::statementHeap()),
routineFlag_(FALSE),
bindWA_(NULL)
{
//cerr << "RETDesc() \t" << this << " " << endl; // ##
}
RETDesc::RETDesc(BindWA* bindWA)
: groupedFlag_(FALSE),
userColumnList_(bindWA->wHeap()),
naTypeForUserColumnList_(CmpCommon::statementHeap()),
systemColumnList_(bindWA->wHeap()),
xtnm_(bindWA->wHeap()),
xcnm_(bindWA->wHeap()),
routineFlag_(FALSE),
bindWA_(bindWA)
{
bindWA->getRETDescList().insert(this);
//cerr << "RETDesc(bwa) \t" << this << " " << endl; // ##
}
RETDesc::RETDesc(BindWA *bindWA, const RETDesc& sourceTable)
: userColumnList_(bindWA->wHeap()),
naTypeForUserColumnList_(CmpCommon::statementHeap()),
systemColumnList_(bindWA->wHeap()),
xtnm_(bindWA->wHeap()),
xcnm_(bindWA->wHeap()),
groupedFlag_(FALSE),
routineFlag_(FALSE),
bindWA_(bindWA)
{
bindWA->getRETDescList().insert(this);
//cerr << "RETDesc(bwa,RD&)\t" << this << " " << (void*)&sourceTable << " " << endl; // ##
addColumns(bindWA, sourceTable);
}
RETDesc::RETDesc(BindWA *bindWA, TableDesc *tdesc, CorrName *newCorrName)
: userColumnList_(bindWA->wHeap()),
naTypeForUserColumnList_(CmpCommon::statementHeap()),
systemColumnList_(bindWA->wHeap()),
xtnm_(bindWA->wHeap()),
xcnm_(bindWA->wHeap()),
groupedFlag_(FALSE),
routineFlag_(FALSE),
bindWA_(bindWA)
{
bindWA->getRETDescList().insert(this);
//cerr << "RETDesc(bwa,TD*)\t" << this << " " << endl; // ##
// Get the corrName, and for performance, apply the defaults to it now,
// before the loop where it is passed down and "defaulted" again and again.
CorrName& corrName = newCorrName ? *newCorrName : tdesc->getCorrNameObj();
NAString cat, sch, tbl;
corrName.extractAndDefaultNameParts(bindWA,
bindWA->getDefaultSchema(),
cat, sch, tbl);
const ValueIdList& vidList = tdesc->getColumnList();
for (CollIndex i = 0; i < vidList.entries(); i++) {
ValueId valId = vidList[i];
CMPASSERT(valId.getItemExpr()->getOperatorType() == ITM_BASECOLUMN);
BaseColumn *baseCol = (BaseColumn *) valId.getItemExpr();
NAColumn *column = baseCol->getNAColumn();
ColRefName colRefName(column->getColName(), corrName,
CmpCommon::statementHeap());
addColumn(bindWA, colRefName, valId,
column->getColumnClass(),
column->getHeading());
}
} // RETDesc::RETDesc()
RETDesc::RETDesc(BindWA *bindWA, RoutineDesc *rdesc, QualifiedName *newQualName)
: userColumnList_(bindWA->wHeap()),
naTypeForUserColumnList_(CmpCommon::statementHeap()),
systemColumnList_(bindWA->wHeap()),
xtnm_(bindWA->wHeap()),
xcnm_(bindWA->wHeap()),
groupedFlag_(FALSE),
routineFlag_(TRUE),
bindWA_(bindWA)
{
bindWA->getRETDescList().insert(this);
//cerr << "RETDesc(bwa,TD*)\t" << this << " " << endl; // ##
// Get the QualifiedName, and for performance, apply the defaults to it now,
// before the loop where it is passed down and "defaulted" again and again.
CMPASSERT(newQualName || (rdesc && rdesc->getNARoutine() &&
rdesc->getNARoutine()->getRoutineName()));
const QualifiedName& qualName = newQualName ? *newQualName :
rdesc->getNARoutine()->getRoutineName()->getQualifiedNameObj();
NAString cat, sch, routine;
qualName.extractAndDefaultNameParts( bindWA->getDefaultSchema(),
cat, sch, routine);
// Only the output parameters of the routine are part of the RETDesc..
const ValueIdList& vidList = rdesc->getOutputColumnList();
const NARoutine *naroutine = NULL;
if (rdesc->isUUDFRoutine()) naroutine = rdesc->getActionNARoutine();
else naroutine = rdesc->getNARoutine();
// if (!naroutine) error.
for (CollIndex i = 0; i < vidList.entries(); i++) {
ValueId valId = vidList[i];
CMPASSERT(valId.getItemExpr()->getOperatorType() == ITM_ROUTINE_PARAM);
RoutineParam *routineOutParam = (RoutineParam *) valId.getItemExpr();
NAColumn *column = naroutine->getParams()[routineOutParam->getOrdinalPos()];
ColRefName colRefName(column->getColName(), qualName,
CmpCommon::statementHeap());
addColumn(bindWA, colRefName, valId,
column->getColumnClass(),
column->getHeading());
}
} // RETDesc::RETDesc()
RETDesc::~RETDesc()
{
systemColumnList_.clearAndDestroy();
userColumnList_.clearAndDestroy();
if (bindWA_)
bindWA_->getRETDescList().remove(this);
//cerr << "~RETDesc~ \t" << this << " bwa=" << bindWA_ << " " << endl; // ##
}
// ***********************************************************************
// RETDesc::addColumn()
// ***********************************************************************
void RETDesc::addColumn(BindWA *bindWA,
const ColRefName& colRefName,
const ValueId valId,
const ColumnClass colClass,
const char *heading)
{
//
// Create a column descriptor, insert it into the column list, and add the
// exposed column name(s) to the hash table.
//
if (colClass == SYSTEM_COLUMN)
addColumnDesc(bindWA, colRefName, valId, heading, systemColumnList_);
else
addColumnDesc(bindWA, colRefName, valId, heading, userColumnList_);
//
// If the column has a qualifier, find the list of columns for that qualifier.
//
// Create that list the first time (even for a "system" column -- see how
// OrderBy processing is done -- this lets errmsg 4001-04 tables-in-scope
// info to be correct).
//
// If the column is a user column, insert it into the list.
//
CorrName corrName(colRefName.getCorrNameObj(), CmpCommon::statementHeap());
if (corrName != "") {
ColumnDescList *columnList = getQualColumnList(corrName);
if (!columnList) {
columnList = new (bindWA->wHeap()) ColumnDescList(bindWA->wHeap());
xtnm_.insertNames(bindWA, corrName, columnList);
}
if (colClass != SYSTEM_COLUMN) {
ColumnDesc *column = userColumnList_[getDegree() - 1];
columnList->insert(column);
}
}
} // RETDesc::addColumn
// ***********************************************************************
// RETDesc::delColumn()
// ***********************************************************************
void RETDesc::delColumn(BindWA *bindWA,
const ColRefName& colRefName,
const ColumnClass colClass)
{
//
// Delete the column descriptor from the column list and the hash table.
//
if (colClass == SYSTEM_COLUMN) {
delColumnDesc(bindWA, colRefName, systemColumnList_);
return;
}
delColumnDesc(bindWA, colRefName, userColumnList_);
//
// If the user column has a qualifier, find the list of columns for that
// qualifier; if such a list exists, delete the column descriptor from it.
//
CorrName corrName(colRefName.getCorrNameObj());
if (corrName != "") {
//
// If a qualified column list has been created, delete column desc from it.
//
ColumnDescList *columnList = getQualColumnList(corrName);
if (columnList) delColumnDesc(bindWA, colRefName, *columnList);
}
} // RETDesc::delColumn
// ***********************************************************************
// RETDesc::addColumnDesc()
// ***********************************************************************
void RETDesc::addColumnDesc(BindWA *bindWA,
const ColRefName& colRefName,
const ValueId valId,
const char *heading,
ColumnDescList& columnList)
{
// Create a column descriptor and insert it into the column list.
//
ColumnDesc *column = new (bindWA->wHeap()) ColumnDesc(colRefName, valId,
heading, bindWA->wHeap());
columnList.insert(column);
// The newSimpleDup logic, in several places below, is to detect one type
// of duplicate column that the XCNM hash table cannot:
// that both "col" and "corr-or-qual.col" appear.
// E.g, the following duplicates (ambiguities) are detected:
// select a,ta.a from ta order by a; -- found by XCNM logic
// select ta.a,a from ta order by a; -- found by XCNM logic
// select * from ta x, ta y order by a; -- found by XCNM logic
// select a,ta.a from ta order by ta.a; -- found by newSimpleDup logic
// select ta.a,a from ta order by ta.a; -- found by newSimpleDup logic
// while preserving the legality of the following:
// select * from ta x, ta y order by x.a,y.a; -- legal!
// select a,ta.a from ta; -- legal, of course
//
// To understand this newSimpleDup logic, first realize that if multiple
// tables are in the FROM-list, then the XCNM logic will disallow references
// to duplicate simple names ("col") in the select-list.
// Thus newSimpleDup only has to deal with queries on one table.
//
ValueId newSimpleDup(NULL_VALUE_ID);
CorrName corrName(colRefName.getCorrNameObj(), CmpCommon::statementHeap());
ExtendedQualName::SpecialTableType specialType = corrName.getSpecialType();
// Add the exposed column name(s) to the hash table.
// First, the simple name "col" ...
//
NAString simpleColNameStr(colRefName.getColName(),
CmpCommon::statementHeap());
ColRefName simpleColRefName(simpleColNameStr);
simpleColRefName.setSpecialType(specialType);
ColumnNameMap *xcnmEntry = findColumn(simpleColRefName);
if (xcnmEntry) {
if (NOT xcnmEntry->isDuplicate())
newSimpleDup = xcnmEntry->getValueId(); // *not* "newSimpleDup = valId"!
xcnmEntry->setDuplicateFlag();
} else
xcnm_.insert(new (bindWA->wHeap()) ColumnNameMap(simpleColRefName, column, bindWA->wHeap()));
if (corrName == "") {
if (newSimpleDup != NULL_VALUE_ID && simpleColNameStr != "") {
// Find previously added xcnm's whose simple name is "col"
// and whose valueId matches, and mark them as dups.
LIST(ColumnNameMap*) xcnmList(CmpCommon::statementHeap());
xcnm_.dump(xcnmList);
for (CollIndex i = 0; i < xcnmList.entries(); i++) {
if (xcnmList[i]->getValueId() == newSimpleDup &&
xcnmList[i]->getColRefNameObj().getColName() == simpleColNameStr)
xcnmList[i]->setDuplicateFlag();
}
}
return;
}
// ... Second, the name "corr-or-qual.col", if "corr" or "qual" is present:
// if "corr", insert "corr.col" into hash table;
// if "qual", insert fully expanded "c.s.t.col" into hash table, plus
// if "c"==default-catalog, insert "s.t.col", plus
// if also "s"==default-schema, insert "t.col".
//
// The insertion and the duplicate flagging allow our later discovery
// of ambiguous column references, e.g.,
// "select * from (select a,b as a from ta) as aa order by aa.a;"
//
// The logic here is similar to that in RETDesc::delColumnDesc and
// XTNM::insertNames -- just a little more complicated (pointers, and
// construction of objects only if needed) because it's a tiny bit more
// efficient in runtime for this most common codepath.
NAString cat, sch, tbl;
Int32 defaultMatch = corrName.extractAndDefaultNameParts(
bindWA,
bindWA->getDefaultSchema(),
cat, sch, tbl);
ColRefName *cstColRefName = NULL, *stColRefName = NULL, *tColRefName = NULL;
const ColRefName *canonicalColRefName;
if (corrName.getCorrNameAsString() != "") {
canonicalColRefName = &colRefName; // "corr.col" just as passed in
CMPASSERT(!defaultMatch);
} else {
cstColRefName = new(bindWA->wHeap())
ColRefName(simpleColNameStr,
CorrName(tbl,bindWA->wHeap(),sch,cat),
bindWA->wHeap());
cstColRefName->setSpecialType(specialType);
canonicalColRefName = cstColRefName; // "c.s.t.col"
if (defaultMatch) {
stColRefName = new(bindWA->wHeap())
ColRefName(simpleColNameStr,
CorrName(tbl,bindWA->wHeap(),sch),
bindWA->wHeap());
stColRefName->setSpecialType(specialType);
if (defaultMatch > 1) {
tColRefName = new(bindWA->wHeap())
ColRefName(simpleColNameStr,
CorrName(tbl),
bindWA->wHeap());
tColRefName->setSpecialType(specialType);
}
}
}
// This first if-test is just a performance hack:
// If simple "col" wasn't a duplicate, "canon.col" can't be, so skip findCol
if (xcnmEntry) {
xcnmEntry = findColumn(*canonicalColRefName);
if (xcnmEntry) {
xcnmEntry->setDuplicateFlag();
if(xcnmEntry->getValueId() != valId){
xcnmEntry->setQualifiedColumnAmbiguousFlag();
}
if (defaultMatch) {
xcnmEntry = findColumn(*stColRefName);
CMPASSERT(xcnmEntry);
xcnmEntry->setDuplicateFlag();
if(xcnmEntry->getValueId() != valId){
xcnmEntry->setQualifiedColumnAmbiguousFlag();
}
if (defaultMatch > 1) {
xcnmEntry = findColumn(*tColRefName);
CMPASSERT(xcnmEntry);
xcnmEntry->setDuplicateFlag();
if(xcnmEntry->getValueId() != valId){
xcnmEntry->setQualifiedColumnAmbiguousFlag();
}
} // "t.col" must be marked as a dup too
} // "s.t.col" must be marked as a dup too
} // "canon.col" was a dup
} // simple "col" was a dup
if (!xcnmEntry) {
// If simple "col" was added on a previous call -- and thus was found
// to be a dup in the logic above -- then mark these xcnm's we are
// about to insert as dups, right off the bat.
NABoolean isDup = newSimpleDup == valId;
xcnm_.insert(new (bindWA->wHeap())
ColumnNameMap(*canonicalColRefName, column, bindWA->wHeap(), isDup));
if (defaultMatch) {
xcnm_.insert(new (bindWA->wHeap())
ColumnNameMap(*stColRefName, column, bindWA->wHeap(), isDup));
if (defaultMatch > 1) {
xcnm_.insert(new (bindWA->wHeap())
ColumnNameMap(*tColRefName, column, bindWA->wHeap(), isDup));
} // "t.col" not dup, must be inserted
} // "s.t.col" not dup, must be inserted
} // "canon.col" not dup, insert
delete cstColRefName;
delete stColRefName;
delete tColRefName;
} // RETDesc::addColumnDesc
// ***********************************************************************
// RETDesc::delColumnDesc()
// ***********************************************************************
void RETDesc::delColumnDesc(BindWA *bindWA,
const ColRefName& colRefName,
ColumnDescList& columnList)
{
//
// Delete all matching column descriptor(s) from the column list.
//
// "if (columnList.remove(&tmpColumn))"
// does not work here, since columnList is a list of pointers,
// i.e. remove does pointer comparisons only (and never finds a match).
for (CollIndex i = 0; i < columnList.entries(); i++) {
ColumnDesc *colDesc = columnList[i];
if (colDesc->getColRefNameObj() == colRefName) {
columnList.remove(colDesc);
break;
}
}
//
// Delete the exposed column name(s) from the hash table.
//
CorrName corrName(colRefName.getCorrNameObj());
ExtendedQualName::SpecialTableType specialType = corrName.getSpecialType();
NAString simpleColNameStr(colRefName.getColName(),
CmpCommon::statementHeap());
ColRefName simpleColRefName(simpleColNameStr);
simpleColRefName.setSpecialType(specialType);
xcnm_.remove(&simpleColRefName);
if (corrName == "") return;
NAString cat, sch, tbl;
Int32 defaultMatch = corrName.extractAndDefaultNameParts(
bindWA,
bindWA->getDefaultSchema(),
cat, sch, tbl);
ColRefName cstColRefName(simpleColNameStr, CorrName(tbl,bindWA->wHeap(),sch,cat));
ColRefName stColRefName(simpleColNameStr, CorrName(tbl,bindWA->wHeap(),sch));
ColRefName tColRefName(simpleColNameStr, CorrName(tbl));
cstColRefName.setSpecialType(specialType);
stColRefName.setSpecialType(specialType);
tColRefName.setSpecialType(specialType);
const ColRefName *canonicalColRefName;
if (corrName.getCorrNameAsString() != "")
canonicalColRefName = &colRefName; // "corr.col"
else
canonicalColRefName = &cstColRefName; // "c.s.t.col"
xcnm_.remove(canonicalColRefName);
if (defaultMatch) {
xcnm_.remove(&stColRefName);
if (defaultMatch > 1)
xcnm_.remove(&tColRefName);
}
} // RETDesc::delColumnDesc
// ***********************************************************************
// RETDesc::nullInstantiateAndAddColumns()
// Operates on the "this" RETDesc, adding columns to it from columnList.
// ***********************************************************************
void RETDesc::nullInstantiateAndAddColumns(BindWA *bindWA,
NABoolean forceCast,
const ColumnDescList& columnList,
const ColumnClass colClass)
{
for (CollIndex i = 0; i < columnList.entries(); i++) {
ValueId nullId = columnList[i]->getValueId().nullInstantiate(bindWA,
forceCast);
addColumn(bindWA, columnList[i]->getColRefNameObj(), nullId, colClass);
}
} // RETDesc::nullInstantiateAndAddColumns
// ***********************************************************************
// RETDesc::nullInstantiate()
// Returns a new RETDesc, the null-instantiated copy of the const "this";
// and appends list of columns to nullOutputList.
// ***********************************************************************
RETDesc *RETDesc::nullInstantiate(BindWA *bindWA,
NABoolean forceCast,
ValueIdList& nullOutputList) const
{
RETDesc *resultTable = new (bindWA->wHeap()) RETDesc();
resultTable->nullInstantiateAndAddColumns(bindWA,
forceCast,
*getColumnList(),
USER_COLUMN);
resultTable->nullInstantiateAndAddColumns(bindWA,
forceCast,
*getSystemColumnList(),
SYSTEM_COLUMN);
resultTable->getValueIdList(nullOutputList, USER_AND_SYSTEM_COLUMNS);
return resultTable;
} // RETDesc::nullInstantiate()
// ***********************************************************************
// RETDesc::findColumn()
// find an entry whose vid matches and is either
// 1. fully-qualified and whose vid matches ...or...
// 2. is a fabricated name
// ***********************************************************************
ColumnNameMap *RETDesc::findColumn(const ValueId vid) const
{
LIST(ColumnNameMap *) colNameMapList(STMTHEAP);
ColumnNameMap *currColNameMap = NULL;
xcnm_.dump(colNameMapList);
for (CollIndex i = 0; i < colNameMapList.entries(); i++)
{
ColumnNameMap *colNameMap = colNameMapList[i];
if (colNameMap->getValueId() EQU vid)
{
const ColRefName &colRefName = colNameMap->getColumnDesc()->
getColRefNameObj();
if (colRefName.isFabricated())
{
return colNameMap;
}
else if (NOT colRefName.isEmpty() AND
colRefName.getCorrNameObj().getQualifiedNameObj().
fullyExpanded())
{
return colNameMap;
}
else if(!currColNameMap ||
(colRefName.getCorrNameObj().getQualifiedNameObj().
numberExpanded() >
currColNameMap->getColumnDesc()->getColRefNameObj().
getCorrNameObj().getQualifiedNameObj().numberExpanded())) {
currColNameMap = colNameMap;
}
}
} // for
return currColNameMap;
} // RETDesc::findColumn()
// ***********************************************************************
// RETDesc::getTableList()
// Returns a list of the FROM-clause tables described by this RETDesc.
// Only one name (the canonical name) for each table ref appears in the list.
// ***********************************************************************
void RETDesc::getTableList(LIST(TableNameMap*) &xtnmList,
NAString *textList) const
{
xtnmList.clear();
xtnm_.dump(xtnmList);
CollIndex i;
// Get rid of dummy entries inserted by XTNM::insertNames().
for (i = xtnmList.entries(); i-- > 0; )
if (!xtnmList[i]->getColumnList())
xtnmList.removeAt(i);
// Separate names by number of parts (corr, tbl, sch.tbl, cat.sch.tbl)
LIST(TableNameMap*) xtnmCORR(STMTHEAP), xtnmT(STMTHEAP);
LIST(TableNameMap*) xtnmST(STMTHEAP), xtnmCST(STMTHEAP);
for (i = 0; i < xtnmList.entries(); i++) {
const CorrName& corr = xtnmList[i]->getTableName();
const QualifiedName& qual = corr.getQualifiedNameObj();
if (!corr.isFabricated())
if (!corr.getCorrNameAsString().isNull())
xtnmCORR.insert(xtnmList[i]);
else if (qual.getSchemaName().isNull())
xtnmT.insert(xtnmList[i]);
else if (qual.getCatalogName().isNull())
xtnmST.insert(xtnmList[i]);
else
xtnmCST.insert(xtnmList[i]);
}
ComASSERT(xtnmCST.entries() >= xtnmST.entries());
ComASSERT(xtnmCST.entries() >= xtnmT.entries());
// Put into the list only the full 3-part names and the correlation names
xtnmList = xtnmCST;
for (i = 0; i < xtnmCORR.entries(); i++)
xtnmList.insert(xtnmCORR[i]);
formatTableList(xtnmList, textList); // a no-op if textList passed as NULL
} // RETDesc::getTableList
/*static*/ void RETDesc::formatTableList(LIST(TableNameMap*) &xtnmList,
NAString *textList,
NABoolean includePartitionName) /*const*/
{
if (!textList) return; // do nothing if passed as NULL
// Sort in ascending order by name, removing any duplicates.
if (xtnmList.entries() > 1) {
LIST(TableNameMap*) xtnmT(STMTHEAP);
xtnmT = xtnmList;
xtnmList.clear();
while (xtnmT.entries()) {
NAString minT(CmpCommon::statementHeap());
if (includePartitionName)
minT = xtnmT[0]->getTableName().getExposedNameAsStringWithPartitionNames();
else
minT = xtnmT[0]->getTableName().getExposedNameAsAnsiString();
CollIndex minTi = 0;
for (CollIndex i = xtnmT.entries() - 1; i > 0; i--) {
NAString T(CmpCommon::statementHeap());
if (includePartitionName)
T = xtnmT[i]->getTableName().getExposedNameAsStringWithPartitionNames();
else
T = xtnmT[i]->getTableName().getExposedNameAsAnsiString();
if (minT > T) {
minT = T; minTi = i; break;
}
else if (minT == T) // remove dups
xtnmT.removeAt(i); // this is why we loop backwards
} // for
if (xtnmList.entries() == 0 || // don't insert dups
xtnmList[xtnmList.entries()-1]->getTableName() !=
xtnmT[minTi]->getTableName())
xtnmList.insert(xtnmT[minTi]);
xtnmT.removeAt(minTi); // been there, seen that minimum
} // while
} // if
for (CollIndex i = 0; i < xtnmList.entries(); i++) {
NAString T(CmpCommon::statementHeap());
if (includePartitionName)
T = xtnmList[i]->getTableName().getExposedNameAsStringWithPartitionNames();
else
T = xtnmList[i]->getTableName().getExposedNameAsAnsiString(FALSE, TRUE);
if (!T.isNull()) { // if not fabricated
if (!textList->isNull())
*textList += ", ";
*textList += T;
if (xtnmList[i]->getTableName().isVolatile())
{
*textList += "(volatile)";
}
}
}
} // RETDesc::formatTableList
// ***********************************************************************
// MVs --
// These methods are only called from a RelRoot or RenameTable nodes when
// the BindWA flag isBindingMvRefresh is set: during CREATE MV, and during
// the binding of an INTERNAL REFRESH command.
// If the RETDesc of the current scope has column called colName - copy
// it over. If the column is already in this RETDesc (by ValueId),
// delete it and insert it again with the original name (NOT of the view).
// ***********************************************************************
void RETDesc::propagateColumn(BindWA *bindWA,
const ColRefName& colName,
NABoolean isFromRoot,
ColumnClass colClass)
{
ColumnNameMap *colMap = NULL;
// Find the column in the RETDesc of the current scope.
RETDesc *retDesc = bindWA->getCurrentScope()->getRETDesc();
if (retDesc != NULL)
colMap = retDesc->findColumn(colName);
if (colMap != NULL)
{
// If it is not in 'this', copy it over.
ColumnNameMap *viewCol = findColumn(colMap->getValueId());
if (viewCol != NULL)
{
NABoolean isSyskeyOfLog =
colName.getCorrNameObj().getSpecialType() == ExtendedQualName::IUD_LOG_TABLE;
if (isFromRoot || isSyskeyOfLog)
return;
else
{
// this RETDesc already has the ValueId - delete it before reinserting.
const ColRefName& viewColRefName =
viewCol->getColumnDesc()->getColRefNameObj();
delColumn(bindWA, viewColRefName, colClass);
}
}
addColumn(bindWA, colMap->getColumnDesc()->getColRefNameObj(),
colMap->getValueId(), colClass);
}
}
// Find the columns to propagate: the @OP column, and the SYSKEY columns
// of the underlying tables.
void RETDesc::propagateOpAndSyskeyColumns(BindWA *bindWA, NABoolean isFromRoot)
{
// Find the SYSKEY and @OP columns from the user column list.
ValueIdList vidList;
RETDesc *source = bindWA->getCurrentScope()->getRETDesc();
if (source == NULL)
return;
source->getValueIdList(vidList, USER_COLUMN);
for (CollIndex i=0; i<vidList.entries(); i++)
{
ColumnNameMap *colMap = source->findColumn(vidList[i]);
if (colMap == NULL)
continue;
const ColRefName& colName =
colMap->getColumnDesc()->getColRefNameObj();
if (colName.getColName() != "SYSKEY" &&
colName.getColName() != MavBuilder::getVirtualOpColumnName())
continue;
propagateColumn(bindWA, colName, isFromRoot, USER_COLUMN);
}
// Find the SYSKEY columns from the system column list.
vidList.clear();
source->getValueIdList(vidList, SYSTEM_COLUMN);
for (CollIndex j=0; j<vidList.entries(); j++)
{
ColumnNameMap *colMap = source->findColumn(vidList[j]);
if (colMap == NULL)
continue;
const ColRefName& colName =
colMap->getColumnDesc()->getColRefNameObj();
if (colName.getColName() != "SYSKEY")
continue;
propagateColumn(bindWA, colName, isFromRoot, SYSTEM_COLUMN);
}
}
// create a list of NATypes corresponding to each entry in the
// userColumnList_ in RETDesc. Used by generator to convert to
// this type during output expr code gen.
// Return: TRUE, if error. FALSE, if all ok.
NABoolean RETDesc::createNATypeForUserColumnList(CollHeap * heap)
{
for (CollIndex i = 0; i < userColumnList_.entries(); i++)
{
const NAType &userColType = userColumnList_[i]->getValueId().getType();
NAType * newType = userColType.newCopy(heap);
naTypeForUserColumnList_.insert(newType);
}
return FALSE;
}
void RETDesc::changeNATypeForUserColumnList(CollIndex index, const NAType * newType)
{
naTypeForUserColumnList_.removeAt(index);
naTypeForUserColumnList_.insertAt(index, (NAType*)newType);
}
// ***********************************************************************
// Display/print, for debugging.
// ***********************************************************************
void RETDesc::display() const { print(); }
void RETDesc::print(FILE* ofd, const char* indent, const char* title) const
{
#ifndef NDEBUG
CollIndex i;
#pragma nowarn(1506) // warning elimination
BUMP_INDENT(indent);
#pragma warn(1506) // warning elimination
fprintf(ofd,"\n NEW RetDesc START \n%s%s %p %s\n --------------------- \n",
NEW_INDENT, title, this,
groupedFlag_ ? "(grouped) " : "");
LIST(TableNameMap*) xtnmList(STMTHEAP);
xtnm_.dump(xtnmList);
for (i = 0; i < xtnmList.entries(); i++)
fprintf(ofd, "%s\n ",
xtnmList[i]->getTableName().getExposedNameAsString().data());
fprintf(ofd,"\n\n\n");
for (i = 0; i < userColumnList_.entries(); i++) {
if (i > 0) fprintf(ofd,",\n ");
userColumnList_[i]->print(ofd, NEW_INDENT, "");
}
if (systemColumnList_.entries()) fprintf(ofd,"\nSYSTEM COLUMNS:\n; ");
for (i = 0; i < systemColumnList_.entries(); i++) {
if (i > 0) fprintf(ofd,", ");
systemColumnList_[i]->print(ofd, NEW_INDENT, "");
}
if (userColumnList_.entries() || systemColumnList_.entries())
fprintf(ofd,"\n\nUSER COLUMNS:\n\n");
LIST(ColumnNameMap*) xcnmList(CmpCommon::statementHeap());
xcnm_.dump(xcnmList);
for (i = 0; i < xcnmList.entries(); i++) {
if (i > 0) fprintf(ofd,",\n");
xcnmList[i]->print(ofd, NEW_INDENT, "");
}
if (i) fprintf(ofd,"\n");
#endif
} // RETDesc::print()
static void displayDownHelper(RelExpr *re, RETDesc *prevRD, int level)
{
RETDesc *thisRD = re->getRETDesc();
char indent[20];
snprintf(indent, sizeof(indent), "Level %4d: ", level);
cout << endl
<< endl
<< indent
<< "====== Operator: " << re->getText().data()
<< endl
<< flush;
if (thisRD != prevRD && thisRD)
thisRD->print(stdout, indent);
else if (thisRD == NULL)
cout << indent << "++++++ RETDesc is NULL" << endl;
else
cout << indent << "++++++ RETDesc is the same as its parent" << endl;
for (int c=0; c<re->getArity(); c++)
{
RelExpr *x = re->child(c);
if (x)
{
cout << indent << "++++++ Child " << c << endl;
displayDownHelper(x, thisRD, level+1);
}
}
} // RETDesc::displayDown
/*static*/ void RETDesc::displayDown(RelExpr *re)
{
displayDownHelper(re, NULL, 1);
} // RETDesc::displayDown