blob: 6cffd006619a25f239be0fcb53590fb657c53dc8 [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: GenMapTable.C
* Description: Methods to handle the map table
*
*
* Created: 4/15/95
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "GenMapTable.h"
#include "ComOptIncludes.h"
#include "dfs2rec.h"
#include "Generator.h"
#include "GenExpGenerator.h"
//////////////////////////////////////////////////////////////////
// class MapInfo
/////////////////////////////////////////////////////////////////
void MapInfo::set(const ValueId & valueId, Attributes * attr, CollHeap * heap)
{
ValueId l_val_id = value_id = valueId;
const ItemExpr *iePtr = l_val_id.getValueDesc()->getItemExpr();
const OperatorTypeEnum operatorType = iePtr->getOperatorType();
if ( operatorType == ITM_VALUEIDREF )
{
l_val_id = ((ValueIdRef *)iePtr)->isDerivedFrom();
}
else if ( operatorType == ITM_INDEXCOLUMN )
{
l_val_id = ((IndexColumn *)iePtr)->getDefinition();
}
// get the data attributes(datatype, length, etc) for this value id.
attr_ = ExpGenerator::convertNATypeToAttributes( l_val_id.getType(),
heap
);
// remember the address(buffer location at runtime)
// attributes for this value id, if attr is passed in.
if (attr)
attr_->copyLocationAttrs(attr);
};
short MapInfo::isOffsetAssigned()
{
if (attr_->getOffset() >= 0)
return -1;
else
return 0;
};
//////////////////////////////////////////////////////////////////
// class MapTable
/////////////////////////////////////////////////////////////////
// ---------------------------------------------------------------------
// addMapEntry()
//
// Add an map info object into this map table.
// Return the pointer to the map info added.
// ---------------------------------------------------------------------
MapInfo * MapTable::addMapInfoToThis(const ValueId & value_id,
Attributes * attr)
{
const CollIndex valueId = value_id;
const Int32 whichMap = valueId / bitsPerUnit;
// --------------------------------------------------
// Do we need to allocate more memory for the bitmaps?
// --------------------------------------------------
if ( whichMap >= vidBitMapArraySize_ )
{
// Double the size needed.
const Int32 newBitMapArraySize = ((vidBitMapArraySize_ == 0)
? (MAXOF(initMTBAsize, 2 * whichMap))
: (2 * whichMap));
// How many bytes is needed for the bitmap array and the integer array.
const Int32 bytesToAllocate =
newBitMapArraySize * (sizeof(MTBitmapUnit) + sizeof(short));
// Allocate memory from statement heap, which is always defined when
// compiling a SQL statement.
char * buffer = new(collHeap()) char[ bytesToAllocate ];
// It is necessary to zero out memory for the bitmap array and
// initialize the integer array to zero.
memset( buffer, 0, bytesToAllocate );
// Assign the allocated memory to the data members.
MTBitmapUnit * newVidBitMapArray = (MTBitmapUnit *) &buffer[ 0 ];
short * newVidsInBitMapArray =
(short *) &buffer[ newBitMapArraySize * sizeof(MTBitmapUnit) ];
if (vidBitMapArraySize_ > 0)
{
// Copy the existing info to the new location.
memcpy(
newVidBitMapArray,
vidBitMapArray_,
vidBitMapArraySize_ * sizeof(MTBitmapUnit)
);
memcpy(
newVidsInBitMapArray,
vidsInBitMapArray_,
vidBitMapArraySize_ * sizeof(short)
);
// Deallocate the value id bitmap array is sufficient.
// Can you figure out why?
NADELETEBASIC( vidBitMapArray_, collHeap() );
}
// Assign the new bitmaps to the map table.
vidBitMapArray_ = newVidBitMapArray;
vidsInBitMapArray_ = newVidsInBitMapArray;
vidBitMapArraySize_ = newBitMapArraySize;
}
// --------------------------------------------------
// Do we need to allocate memory for the map info?
// --------------------------------------------------
if ( totalVids_ >= mapInfoPtrArraySize_ )
{
Int32 newMapInfoPtrArraySize =
((mapInfoPtrArraySize_ == 0)
? initMTMIPAsize
: mapInfoPtrArraySize_ + mapInfoPtrArrayStepSize);
MapInfo ** newMapInfoPtrArray =
new(collHeap()) MapInfo * [ newMapInfoPtrArraySize ];
#ifdef _DEBUG
// Initialize the map info array to repeating sequence of 1011.
// Make it eye-catching and if we ever try dereferencing
// an odd pointer, it'll crash.
for ( Int32 i = 0; i < newMapInfoPtrArraySize; i++ )
{
newMapInfoPtrArray[i] = (MapInfo *)0xBBBBBBBB;
}
#endif
if (mapInfoPtrArraySize_ > 0)
{
// Copy the existing info to the new location.
memcpy(
newMapInfoPtrArray,
mapInfoPtrArray_,
mapInfoPtrArraySize_ * sizeof(MapInfo *)
);
// Deallocate memory for old map info array.
NADELETEBASIC( mapInfoPtrArray_, collHeap() );
}
// Assign the new map info array to the map table.
mapInfoPtrArray_ = newMapInfoPtrArray;
mapInfoPtrArraySize_ = newMapInfoPtrArraySize;
}
// --------------------------------------------------
// Get the index into the map info array.
// --------------------------------------------------
#ifdef _DEBUG
MTBitmapUnit bits = getBits( valueId, whichMap );
#endif
Int32 index = getIndexIntoMapInfoPtrArray( whichMap,
getBits( valueId, whichMap )
);
// --------------------------------------------------
// Move map infos around if necessary.
// --------------------------------------------------
Int32 mapInfosLeftToMove;
if ( (mapInfosLeftToMove = totalVids_ - index) > 0 )
{
// Some map infos are behind me in the map info array. Move them.
// This will happen when value ids are not inserted in ascending order.
// Let's move 8 pointers at a time.
#define moveXMapInfoPtrsAtATime 8
MapInfo * tmpMapInfoPtrArray[ moveXMapInfoPtrsAtATime ];
Int32 end = totalVids_;
while ( mapInfosLeftToMove > 0 )
{
const Int32 ptrsToMove = ( mapInfosLeftToMove > moveXMapInfoPtrsAtATime )
? moveXMapInfoPtrsAtATime
: mapInfosLeftToMove;
const Int32 bytesToMove = sizeof(MapInfo *) * ptrsToMove;
// Copy to a local array.
memcpy(
tmpMapInfoPtrArray,
&mapInfoPtrArray_[end - ptrsToMove],
bytesToMove
);
// Copy back to the original array.
memcpy(
&mapInfoPtrArray_[end + 1 - ptrsToMove],
tmpMapInfoPtrArray,
bytesToMove
);
end -= moveXMapInfoPtrsAtATime;
mapInfosLeftToMove -= moveXMapInfoPtrsAtATime;
}
}
// --------------------------------------------------
// Finally, the real deal.
// --------------------------------------------------
// Flip the bit corresponding to the value id 'ON'
// by left shifting to the correct bit position.
*(vidBitMapArray_ + whichMap) |=
(0x1 << (bitsPerUnitMinus1 - (valueId % bitsPerUnit)));
// Allocate a new MapInfo entry and insert it into the map info array.
Int32 containerIndex = totalVids_ % MICAsize;
if (containerIndex == 0)
{
MapInfoContainer * mic = new(collHeap()) MapInfoContainer(collHeap());
if (firstMapInfoContainer_ == NULL)
{
firstMapInfoContainer_ = mic;
lastMapInfoContainer_ = mic;
}
else
{
lastMapInfoContainer_->next_ = mic;
lastMapInfoContainer_ = mic;
}
}
MapInfo * mapEntry =&(lastMapInfoContainer_->mapInfoArray_[containerIndex]);
// MapInfo * mapEntry = new(collHeap()) MapInfo();
mapEntry->set(value_id, attr, collHeap());
*(mapInfoPtrArray_ + index) = mapEntry;
// Update counters.
(*(vidsInBitMapArray_ + whichMap))++;
totalVids_++;
#ifdef _DEBUG
if (getenv("IM_DEBUG"))
cerr << "addMapEntry: " << this << " " << value_id << "\t"
<< attr << "\t me=" << mapEntry << endl;
// Sanity checks.
Int32 numVids = 0;
for ( Int32 i = 0; i < vidBitMapArraySize_; i++ )
{
numVids += vidsInBitMapArray_[i];
}
CMPASSERT( totalVids_ == numVids );
#endif
// Return the map info.
return mapEntry;
}
// ---------------------------------------------------------------------
// getMapEntry()
//
// Get a pointer to a MapInfo that corresponds to the value id.
// Return NULL if not found.
// ---------------------------------------------------------------------
MapInfo * MapTable::getMapInfoFromThis(const ValueId & value_id)
{
// --------------------------------------------------
// Find the bits in the bitmap that we're interested in.
// --------------------------------------------------
const CollIndex valueId = value_id;
const Int32 whichMap = valueId / bitsPerUnit;
// Range check.
if ( whichMap >= vidBitMapArraySize_ )
{
// Value Id not found. Out of bitmap range.
return NULL;
}
MTBitmapUnit bits = getBits( valueId, whichMap );
if ( 0 == (bits & 0x1) )
{
// Value Id not found. It is not in this map table.
return NULL;
}
// --------------------------------------------------
// Return the map info pointer.
// --------------------------------------------------
#ifdef _DEBUG
Int32 index = getIndexIntoMapInfoPtrArray( whichMap, bits );
MapInfo * mapInfo = mapInfoPtrArray_[index];
return mapInfo;
#else
return *(mapInfoPtrArray_ + getIndexIntoMapInfoPtrArray( whichMap, bits ));
#endif // _DEBUG
}
void MapTable::setAllAtp(short Atp)
{
MapTable *me = this;
do
{
for ( Int32 i = 0; i < me->totalVids_; i++ )
{
#ifdef _DEBUG
MapInfo *info = *(me->mapInfoPtrArray_ + i);
Attributes *attr = info->getAttr();
#else
Attributes *attr = (*(me->mapInfoPtrArray_ + i))->getAttr();
#endif
if ( (attr != NULL) && (attr->getAtpIndex() > 1) )
{
// Only change the atp if the ATP index is greater than 1.
// This excludes constants, temps, and persistents.
//
attr->setAtp( Atp );
}
}
me = me->next_;
}
while ( me != NULL );
}
void MapTable::resetCodeGen()
{
MapTable *me = this;
do
{
for ( Int32 i = 0; i < me->totalVids_; i++ )
{
MapInfo *info = *(me->mapInfoPtrArray_ + i);
info->resetCodeGenerated();
}
me = me->next_;
}
while ( me != NULL );
}
void MapTable::shiftAtpIndex(short shiftIndex)
{
MapTable *me = this;
do
{
for ( Int32 i = 0; i < me->totalVids_; i++ )
{
#ifdef _DEBUG
MapInfo *info = *(me->mapInfoPtrArray_ + i);
Attributes *attr = info->getAttr();
#else
Attributes *attr = (*(me->mapInfoPtrArray_ + i))->getAttr();
#endif
if ( (attr != NULL) && (attr->getAtpIndex() > 1) )
{
// Only change the atp if the original ATP index is greater
// than 1. This excludes constants, temps, and persistents.
//
attr->setAtpIndex( attr->getAtpIndex() + shiftIndex );
}
}
me = me ->next_;
}
while ( me != NULL );
}
// ---------------------------------------------------------------------
// getIndexIntoMapInfoPtrArray()
//
// Get the index into the map info array.
// Inputs: whichMap -- the bitmap the value id is in
// bits -- the relevant bits that we're interested in
// ---------------------------------------------------------------------
Int32 MapTable::getIndexIntoMapInfoPtrArray(
const Int32 whichMap,
MTBitmapUnit inBits
) const
{
#ifdef _DEBUG
DCMPASSERT( whichMap >= 0 AND whichMap < vidBitMapArraySize_ );
#endif
// --------------------------------------------------
// It is the sum of the number of value ids that is
// smaller than me in this map table.
// --------------------------------------------------
Int32 arrayIndex = 0;
// --------------------------------------------------
// First, add up the number of value ids in the bitmaps before me.
// --------------------------------------------------
for ( Int32 i = 0; i < whichMap; i++ )
{
arrayIndex += *(vidsInBitMapArray_ + i);
}
// --------------------------------------------------
// Next, add up the number of value ids in the same bitmap as me.
// --------------------------------------------------
#ifdef _DEBUG
// This is done differently than the release version.
// See the explanation below.
for ( Int32 k = 0; k < bitsPerUnit && inBits != 0; k++ )
{
// Right shift 1 bit.
// If the least significant bit is 'ON', add index by 1.
inBits >>= 1;
arrayIndex += (inBits & 0x1);
}
// By this time, all the bits should have been shifted and
// none of the bits should be 'ON'.
CMPASSERT( 0 == (inBits & 0x1) );
#else
// Right shift 1 bit. Keep looping as long as one of the bits is 'ON'.
while ( 0 != (inBits >>= 1) )
{
// If the least significant bit is 'ON', add index by 1.
arrayIndex += (inBits & 0x1);
}
#endif // _DEBUG
// Sanity check.
#ifdef _DEBUG
DCMPASSERT( arrayIndex >= 0 AND arrayIndex <= totalVids_ );
#endif
return arrayIndex;
}
#ifdef _DEBUG
void MapTable::print()
{
printToFile(stdout);
}
void MapTable::printToFile(FILE *f)
{
// header for each map table
fprintf(f, "Map Table: %p\n", this);
// print each map info (value id, unparsed text, attributes, if present)
for ( Int32 i = 0; i < totalVids_; i++ )
{
MapInfo *info = mapInfoPtrArray_[i];
Attributes *attr = info->getAttr();
NAString unparsed;
// ValueId <xx> (generated) (<unparsed>):
fprintf(f, " ValueId %d", (CollIndex) info->getValueId());
if (info->isCodeGenerated())
fprintf(f, " (generated)");
else
fprintf(f, " ");
info->getValueId().getItemExpr()->unparse(unparsed);
fprintf(f, " (%s):\n", unparsed.data());
if (attr)
{
// atp = <atp>, atpindex = <atpindex>, offset = <offset>
// type = <fs type>, null = <nullable>
fprintf(f, " atp = %2d", attr->getAtp());
fprintf(f, ", atpindex = %2d", attr->getAtpIndex());
fprintf(f, ", offset = %3d", attr->getOffset());
fprintf(f, ", fstype = %3d", attr->getDatatype());
fprintf(f, ", tupleFormat = %2d", attr->getTupleFormat());
fprintf(f, ", %s\n", (attr->getNullFlag() ?
"Nullable" : "Not nullable"));
}
}
if (next_)
next_->printToFile(f);
else
fprintf(f, "--------------------------------------------------------\n");
}
#endif