mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-06-06 08:21:01 +03:00
* TEXT and BLOB now have separate identifiers internally * TEXT columns are identified as such in system catalog * cpimport only requires hex input for BLOB, not TEXT
918 lines
24 KiB
C++
918 lines
24 KiB
C++
/* Copyright (C) 2014 InfiniDB, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; version 2 of
|
|
the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
//
|
|
// $Id: columncommand.cpp 2057 2013-02-13 17:00:10Z pleblanc $
|
|
// C++ Implementation: columncommand
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Author: Patrick LeBlanc <pleblanc@calpont.com>, (C) 2008
|
|
// Copyright: See COPYING file that comes with this distribution
|
|
//
|
|
//
|
|
|
|
#include <unistd.h>
|
|
#include <sstream>
|
|
#include <map>
|
|
#include <cstdlib>
|
|
#include <cmath>
|
|
using namespace std;
|
|
|
|
#include "bpp.h"
|
|
#include "errorcodes.h"
|
|
#include "exceptclasses.h"
|
|
#include "primitiveserver.h"
|
|
#include "primproc.h"
|
|
#include "stats.h"
|
|
|
|
using namespace messageqcpp;
|
|
using namespace rowgroup;
|
|
|
|
#include "messageids.h"
|
|
using namespace logging;
|
|
|
|
#ifdef _MSC_VER
|
|
#define llabs labs
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
using namespace primitiveprocessor;
|
|
|
|
double cotangent(double in)
|
|
{
|
|
return (1.0 / tan(in));
|
|
}
|
|
|
|
}
|
|
|
|
namespace primitiveprocessor
|
|
{
|
|
|
|
extern int noVB;
|
|
|
|
ColumnCommand::ColumnCommand() :
|
|
Command(COLUMN_COMMAND),
|
|
blockCount(0),
|
|
loadCount(0),
|
|
suppressFilter(false)
|
|
{
|
|
}
|
|
|
|
ColumnCommand::~ColumnCommand() { }
|
|
|
|
void ColumnCommand::_execute()
|
|
{
|
|
// cout << "CC: executing" << endl;
|
|
if (_isScan)
|
|
makeScanMsg();
|
|
else if (bpp->ridCount == 0) { // this would cause a scan
|
|
blockCount += colType.colWidth;
|
|
return; // a step with no input rids does nothing
|
|
}
|
|
else
|
|
makeStepMsg();
|
|
issuePrimitive();
|
|
processResult();
|
|
|
|
// check if feeding a filtercommand
|
|
if (fFilterFeeder != NOT_FEEDER)
|
|
copyRidsForFilterCmd();
|
|
}
|
|
|
|
void ColumnCommand::execute()
|
|
{
|
|
if (fFilterFeeder == LEFT_FEEDER)
|
|
values = bpp->fFiltCmdValues[0].get();
|
|
else if (fFilterFeeder == RIGHT_FEEDER)
|
|
values = bpp->fFiltCmdValues[1].get();
|
|
else
|
|
values = bpp->values;
|
|
_execute();
|
|
}
|
|
|
|
void ColumnCommand::execute(int64_t *vals)
|
|
{
|
|
values = vals;
|
|
_execute();
|
|
}
|
|
|
|
void ColumnCommand::makeScanMsg()
|
|
{
|
|
/* Finish the NewColRequestHeader. */
|
|
|
|
/* XXXPAT: if there is a Command preceeding this one, it's a DictScan feeding tokens
|
|
which need to become filter elements. Can we handle that with this design?
|
|
Implement that later. */
|
|
|
|
primMsg->ism.Size = baseMsgLength;
|
|
primMsg->NVALS = 0;
|
|
primMsg->LBID = lbid;
|
|
primMsg->RidFlags = 0xFF;
|
|
|
|
// cout << "scanning lbid " << lbid << " colwidth = " << primMsg->DataSize <<
|
|
// " filterCount = " << filterCount << " outputType = " <<
|
|
// (int) primMsg->OutputType << endl;
|
|
}
|
|
|
|
void ColumnCommand::makeStepMsg()
|
|
{
|
|
memcpy(&inputMsg[baseMsgLength], bpp->relRids, bpp->ridCount << 1);
|
|
primMsg->RidFlags = bpp->ridMap;
|
|
primMsg->ism.Size = baseMsgLength + (bpp->ridCount << 1);
|
|
primMsg->NVALS = bpp->ridCount;
|
|
primMsg->LBID = lbid;
|
|
// cout << "lbid is " << lbid << endl;
|
|
}
|
|
|
|
void ColumnCommand::loadData()
|
|
{
|
|
uint32_t wasCached;
|
|
uint32_t blocksRead;
|
|
uint8_t _mask;
|
|
uint64_t oidLastLbid=0;
|
|
bool lastBlockReached=false;
|
|
oidLastLbid = getLastLbid();
|
|
uint32_t blocksToLoad = 0;
|
|
BRM::LBID_t *lbids = (BRM::LBID_t *) alloca(8 * sizeof(BRM::LBID_t));
|
|
uint8_t **blockPtrs = (uint8_t **) alloca(8 * sizeof(uint8_t *));
|
|
int i;
|
|
|
|
|
|
_mask = mask;
|
|
// primMsg->RidFlags = 0xff; // disables selective block loading
|
|
//cout <<__FILE__ << "::issuePrimitive() o: " << getOID() << " l:" << primMsg->LBID << " ll: " << oidLastLbid << endl;
|
|
|
|
for (i=0; i < colType.colWidth; ++i, _mask <<= shift) {
|
|
|
|
if ((!lastBlockReached && _isScan) || (!_isScan && primMsg->RidFlags & _mask)) {
|
|
lbids[blocksToLoad] = primMsg->LBID + i;
|
|
blockPtrs[blocksToLoad] = &bpp->blockData[i * BLOCK_SIZE];
|
|
blocksToLoad++;
|
|
loadCount++;
|
|
}
|
|
else if (lastBlockReached && _isScan)
|
|
{ // fill remaining blocks with empty values when col scan
|
|
int blockLen = BLOCK_SIZE/colType.colWidth;
|
|
ByteStream::octbyte* oPtr=NULL;
|
|
ByteStream::quadbyte* qPtr=NULL;
|
|
ByteStream::byte* bPtr=NULL;
|
|
ByteStream::doublebyte* dPtr=NULL;
|
|
if (colType.colWidth==1)
|
|
bPtr = reinterpret_cast<ByteStream::byte*>(&bpp->blockData[i*BLOCK_SIZE]);
|
|
//@Bug 1812. Added two bytes column handling
|
|
if (colType.colWidth==2)
|
|
dPtr = reinterpret_cast<ByteStream::doublebyte*>(&bpp->blockData[i*BLOCK_SIZE]);
|
|
if (colType.colWidth==4)
|
|
qPtr = reinterpret_cast<ByteStream::quadbyte*>(&bpp->blockData[i*BLOCK_SIZE]);
|
|
if (colType.colWidth==8)
|
|
oPtr = reinterpret_cast<ByteStream::octbyte*>(&bpp->blockData[i*BLOCK_SIZE]);
|
|
|
|
for (int idx=0; idx < blockLen; idx++)
|
|
{
|
|
if (bPtr && colType.colWidth==1) {
|
|
ByteStream::byte b = getEmptyRowValue(colType.colDataType, colType.colWidth);
|
|
bPtr[idx] = b;
|
|
}
|
|
//@Bug 1812. Added two bytes column handling
|
|
else if (dPtr && colType.colWidth==2) {
|
|
ByteStream::doublebyte d = getEmptyRowValue(colType.colDataType, colType.colWidth);
|
|
dPtr[idx] = d;
|
|
}
|
|
else if (qPtr && colType.colWidth==4) {
|
|
ByteStream::quadbyte q = getEmptyRowValue(colType.colDataType, colType.colWidth);
|
|
qPtr[idx] = q;
|
|
}
|
|
else if (oPtr && colType.colWidth==8) {
|
|
ByteStream::octbyte o = getEmptyRowValue(colType.colDataType, colType.colWidth);
|
|
oPtr[idx] = o;
|
|
}
|
|
}
|
|
|
|
}// else
|
|
|
|
if ( (primMsg->LBID+i)==oidLastLbid)
|
|
lastBlockReached=true;
|
|
blockCount++;
|
|
} // for
|
|
|
|
/* Do the load */
|
|
wasCached = primitiveprocessor::loadBlocks(lbids,
|
|
bpp->versionInfo,
|
|
bpp->txnID,
|
|
colType.compressionType,
|
|
blockPtrs,
|
|
&blocksRead,
|
|
bpp->LBIDTrace,
|
|
bpp->sessionID,
|
|
blocksToLoad,
|
|
&wasVersioned,
|
|
willPrefetch(),
|
|
&bpp->vssCache);
|
|
bpp->cachedIO += wasCached;
|
|
bpp->physIO += blocksRead;
|
|
bpp->touchedBlocks += blocksToLoad;
|
|
}
|
|
|
|
void ColumnCommand::issuePrimitive()
|
|
{
|
|
uint32_t resultSize;
|
|
|
|
loadData();
|
|
|
|
// cout << "issuing primitive for LBID " << primMsg->LBID << endl;
|
|
if (!suppressFilter)
|
|
bpp->pp.setParsedColumnFilter(parsedColumnFilter);
|
|
else
|
|
bpp->pp.setParsedColumnFilter(emptyFilter);
|
|
bpp->pp.p_Col(primMsg, outMsg, bpp->outMsgSize, (unsigned int*)&resultSize);
|
|
|
|
/* Update CP data, the PseudoColumn code should always be !_isScan. Should be safe
|
|
to leave this here for now. */
|
|
if (_isScan) {
|
|
bpp->validCPData = (outMsg->ValidMinMax && !wasVersioned);
|
|
//if (wasVersioned && outMsg->ValidMinMax)
|
|
// cout << "CC: versioning overriding min max data\n";
|
|
bpp->lbidForCP = lbid;
|
|
bpp->maxVal = outMsg->Max;
|
|
bpp->minVal = outMsg->Min;
|
|
}
|
|
|
|
} // issuePrimitive()
|
|
|
|
void ColumnCommand::process_OT_BOTH()
|
|
{
|
|
uint64_t i, pos;
|
|
|
|
bpp->ridCount = outMsg->NVALS;
|
|
bpp->ridMap = outMsg->RidFlags;
|
|
// cout << "rid Count is " << bpp->ridCount << endl;
|
|
|
|
/* this is verbose and repetative to minimize the work per row */
|
|
switch(colType.colWidth) {
|
|
case 8:
|
|
for (i = 0, pos = sizeof(NewColResultHeader); i < outMsg->NVALS; ++i) {
|
|
if (makeAbsRids)
|
|
bpp->absRids[i] = *((uint16_t *) &bpp->outputMsg[pos]) + bpp->baseRid;
|
|
bpp->relRids[i] = *((uint16_t *) &bpp->outputMsg[pos]);
|
|
pos += 2;
|
|
values[i] = *((int64_t *) &bpp->outputMsg[pos]);
|
|
pos += 8;
|
|
}
|
|
break;
|
|
case 4:
|
|
for (i = 0, pos = sizeof(NewColResultHeader); i < outMsg->NVALS; ++i) {
|
|
if (makeAbsRids)
|
|
bpp->absRids[i] = *((uint16_t *) &bpp->outputMsg[pos]) + bpp->baseRid;
|
|
bpp->relRids[i] = *((uint16_t *) &bpp->outputMsg[pos]);
|
|
pos += 2;
|
|
values[i] = *((int32_t *) &bpp->outputMsg[pos]);
|
|
pos += 4;
|
|
}
|
|
break;
|
|
case 2:
|
|
for (i = 0, pos = sizeof(NewColResultHeader); i < outMsg->NVALS; ++i) {
|
|
if (makeAbsRids)
|
|
bpp->absRids[i] = *((uint16_t *) &bpp->outputMsg[pos]) + bpp->baseRid;
|
|
bpp->relRids[i] = *((uint16_t *) &bpp->outputMsg[pos]);
|
|
pos += 2;
|
|
values[i] = *((int16_t *) &bpp->outputMsg[pos]);
|
|
pos += 2;
|
|
}
|
|
break;
|
|
case 1:
|
|
for (i = 0, pos = sizeof(NewColResultHeader); i < outMsg->NVALS; ++i) {
|
|
if (makeAbsRids)
|
|
bpp->absRids[i] = *((uint16_t *) &bpp->outputMsg[pos]) + bpp->baseRid;
|
|
bpp->relRids[i] = *((uint16_t *) &bpp->outputMsg[pos]);
|
|
pos += 2;
|
|
values[i] = *((int8_t *) &bpp->outputMsg[pos++]);
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void ColumnCommand::process_OT_RID()
|
|
{
|
|
memcpy(bpp->relRids, outMsg + 1, outMsg->NVALS << 1);
|
|
bpp->ridCount = outMsg->NVALS;
|
|
bpp->ridMap = outMsg->RidFlags;
|
|
// cout << "rid Count is " << bpp->ridCount << endl;
|
|
}
|
|
|
|
void ColumnCommand::process_OT_DATAVALUE()
|
|
{
|
|
bpp->ridCount = outMsg->NVALS;
|
|
// cout << "rid Count is " << bpp->ridCount << endl;
|
|
switch(colType.colWidth) {
|
|
case 8:
|
|
{
|
|
memcpy(values, outMsg + 1, outMsg->NVALS << 3);
|
|
// cout << " CC: first value is " << values[0] << endl;
|
|
break;
|
|
}
|
|
case 4:
|
|
{
|
|
int32_t* arr32 = (int32_t *) (outMsg + 1);
|
|
for (uint64_t i = 0; i < outMsg->NVALS; ++i)
|
|
values[i] = arr32[i];
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
int16_t* arr16 = (int16_t *) (outMsg + 1);
|
|
for (uint64_t i = 0; i < outMsg->NVALS; ++i)
|
|
values[i] = arr16[i];
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
int8_t* arr8 = (int8_t *) (outMsg + 1);
|
|
for (uint64_t i = 0; i < outMsg->NVALS; ++i)
|
|
values[i] = arr8[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ColumnCommand::processResult()
|
|
{
|
|
/* Switch on output type, turn pCol output into something useful, store it in
|
|
the containing BPP */
|
|
|
|
// if (filterCount == 0 && !_isScan)
|
|
// idbassert(outMsg->NVALS == bpp->ridCount);
|
|
|
|
switch (outMsg->OutputType) {
|
|
case OT_BOTH:
|
|
process_OT_BOTH();
|
|
break;
|
|
case OT_RID:
|
|
process_OT_RID();
|
|
break;
|
|
case OT_DATAVALUE:
|
|
process_OT_DATAVALUE();
|
|
break;
|
|
default:
|
|
cout << "outputType = " << outMsg->OutputType << endl;
|
|
throw logic_error("ColumnCommand got a bad OutputType");
|
|
}
|
|
|
|
// check if feeding a filtercommand
|
|
if (fFilterFeeder == LEFT_FEEDER)
|
|
{
|
|
bpp->fFiltRidCount[0] = bpp->ridCount;
|
|
for (uint64_t i = 0; i < bpp->ridCount; i++)
|
|
bpp->fFiltCmdRids[0][i] = bpp->relRids[i];
|
|
}
|
|
else if (fFilterFeeder == RIGHT_FEEDER)
|
|
{
|
|
bpp->fFiltRidCount[1] = bpp->ridCount;
|
|
for (uint64_t i = 0; i < bpp->ridCount; i++)
|
|
bpp->fFiltCmdRids[1][i] = bpp->relRids[i];
|
|
}
|
|
// cout << "processed " << outMsg->NVALS << " rows" << endl;
|
|
}
|
|
|
|
void ColumnCommand::createCommand(ByteStream &bs)
|
|
{
|
|
uint8_t tmp8;
|
|
|
|
bs.advance(1);
|
|
bs >> tmp8;
|
|
_isScan = tmp8;
|
|
bs >> traceFlags;
|
|
bs >> filterString;
|
|
#if 0
|
|
cout << "filter string: ";
|
|
for (uint32_t i = 0; i < filterString.length(); ++i)
|
|
cout << (int) filterString.buf()[i] << " ";
|
|
cout << endl;
|
|
#endif
|
|
bs >> tmp8;
|
|
colType.colDataType = (execplan::CalpontSystemCatalog::ColDataType) tmp8;
|
|
bs >> tmp8;
|
|
colType.colWidth = tmp8;
|
|
bs >> tmp8;
|
|
colType.scale = tmp8;
|
|
bs >> tmp8;
|
|
colType.compressionType = tmp8;
|
|
bs >> BOP;
|
|
bs >> filterCount;
|
|
deserializeInlineVector(bs, lastLbid);
|
|
// cout << "lastLbid count=" << lastLbid.size() << endl;
|
|
// for (uint32_t i = 0; i < lastLbid.size(); i++)
|
|
// cout << " " << lastLbid[i];
|
|
|
|
|
|
//cout << "CreateCommand() o:" << getOID() << " lastLbid: " << lastLbid << endl;
|
|
Command::createCommand(bs);
|
|
|
|
parsedColumnFilter = primitives::parseColumnFilter(filterString.buf(), colType.colWidth,
|
|
colType.colDataType, filterCount, BOP);
|
|
|
|
/* OR hack */
|
|
emptyFilter = primitives::parseColumnFilter(filterString.buf(), colType.colWidth,
|
|
colType.colDataType, 0, BOP);
|
|
|
|
/* XXXPAT: for debugging only */
|
|
// bs >> colType.columnOID;
|
|
// cout << "got filterCount " << filterCount << endl;
|
|
// cout << "made a ColumnCommand OID = " << OID << endl;
|
|
}
|
|
|
|
void ColumnCommand::resetCommand(ByteStream &bs)
|
|
{
|
|
bs >> lbid;
|
|
}
|
|
|
|
void ColumnCommand::prep(int8_t outputType, bool absRids)
|
|
{
|
|
/* make the template NewColRequestHeader */
|
|
|
|
baseMsgLength = sizeof(NewColRequestHeader) +
|
|
(suppressFilter ? 0 : filterString.length());
|
|
|
|
if (!inputMsg)
|
|
inputMsg.reset(new uint8_t[baseMsgLength + (LOGICAL_BLOCK_RIDS * 2)]);
|
|
primMsg = (NewColRequestHeader *) inputMsg.get();
|
|
outMsg = (NewColResultHeader *) bpp->outputMsg.get();
|
|
makeAbsRids = absRids;
|
|
|
|
primMsg->ism.Interleave = 0;
|
|
primMsg->ism.Flags = 0;
|
|
// primMsg->ism.Flags = PrimitiveMsg::planFlagsToPrimFlags(traceFlags);
|
|
primMsg->ism.Command=COL_BY_SCAN;
|
|
primMsg->ism.Size = sizeof(NewColRequestHeader) + (suppressFilter ? 0 : filterString.length());
|
|
primMsg->ism.Type = 2;
|
|
primMsg->hdr.SessionID = bpp->sessionID;
|
|
//primMsg->hdr.StatementID = 0;
|
|
primMsg->hdr.TransactionID = bpp->txnID;
|
|
primMsg->hdr.VerID = bpp->versionInfo.currentScn;
|
|
primMsg->hdr.StepID = bpp->stepID;
|
|
primMsg->DataSize = colType.colWidth;
|
|
primMsg->DataType = colType.colDataType;
|
|
primMsg->CompType = colType.compressionType;
|
|
primMsg->OutputType = outputType;
|
|
primMsg->BOP = BOP;
|
|
primMsg->NOPS = (suppressFilter ? 0 : filterCount);
|
|
primMsg->sort = 0;
|
|
#if 0
|
|
cout << "filter length is " << filterString.length() << endl;
|
|
|
|
cout << "appending filter string: ";
|
|
for (uint32_t i = 0; i < filterString.length(); ++i)
|
|
cout << (int) filterString.buf()[i] << " ";
|
|
cout << endl;
|
|
#endif
|
|
// made unnecessary by parsedColumnFilter, just leave empty space as if the filter
|
|
// were still there.
|
|
// memcpy(primMsg + 1, filterString.buf(), filterString.length());
|
|
|
|
|
|
|
|
switch (colType.colWidth) {
|
|
case 1:
|
|
shift = 8;
|
|
mask = 0xFF;
|
|
break;
|
|
case 2:
|
|
shift = 4;
|
|
mask = 0x0F;
|
|
break;
|
|
case 4:
|
|
shift = 2;
|
|
mask = 0x03;
|
|
break;
|
|
case 8:
|
|
shift = 1;
|
|
mask = 0x01;
|
|
break;
|
|
default:
|
|
cout << "CC: colWidth is " << colType.colWidth << endl;
|
|
throw logic_error("ColumnCommand: bad column width?");
|
|
}
|
|
|
|
/* TODO: re-optimize with parameterized output RG */
|
|
// if (bpp->ot == ROW_GROUP) {
|
|
// bpp->outputRG.initRow(&r);
|
|
// rowSize = r.getSize();
|
|
// }
|
|
|
|
}
|
|
|
|
/* Assumes OT_DATAVALUE */
|
|
void ColumnCommand::projectResult()
|
|
{
|
|
if (primMsg->NVALS != outMsg->NVALS || outMsg->NVALS != bpp->ridCount )
|
|
{
|
|
ostringstream os;
|
|
BRM::DBRM brm;
|
|
BRM::OID_t oid;
|
|
uint16_t l_dbroot;
|
|
uint32_t partNum;
|
|
uint16_t segNum;
|
|
uint32_t fbo;
|
|
brm.lookupLocal(lbid, 0, false, oid, l_dbroot, partNum, segNum, fbo);
|
|
|
|
os << __FILE__ << " error on projection for oid " << oid << " lbid " << lbid;
|
|
if (primMsg->NVALS != outMsg->NVALS )
|
|
os << ": input rids " << primMsg->NVALS;
|
|
else
|
|
os << ": ridcount " << bpp->ridCount;
|
|
os << ", output rids " << outMsg->NVALS << endl;
|
|
//cout << os.str();
|
|
if (bpp->sessionID & 0x80000000)
|
|
throw NeedToRestartJob(os.str());
|
|
else
|
|
throw PrimitiveColumnProjectResultExcept(os.str());
|
|
}
|
|
idbassert(primMsg->NVALS == outMsg->NVALS);
|
|
idbassert(outMsg->NVALS == bpp->ridCount);
|
|
*bpp->serialized << (uint32_t) (outMsg->NVALS * colType.colWidth);
|
|
bpp->serialized->append((uint8_t *) (outMsg + 1), outMsg->NVALS * colType.colWidth);
|
|
}
|
|
|
|
void ColumnCommand::removeRowsFromRowGroup(RowGroup &rg)
|
|
{
|
|
uint32_t gapSize = colType.colWidth + 2;
|
|
uint8_t *msg8;
|
|
uint16_t rid;
|
|
Row oldRow, newRow;
|
|
uint32_t oldIdx, newIdx;
|
|
|
|
rg.initRow(&oldRow);
|
|
rg.initRow(&newRow);
|
|
rg.getRow(0, &oldRow);
|
|
rg.getRow(0, &newRow);
|
|
msg8 = (uint8_t *) (outMsg + 1);
|
|
for (oldIdx = newIdx = 0; newIdx < outMsg->NVALS; newIdx++, msg8 += gapSize) {
|
|
rid = *((uint16_t *) msg8);
|
|
while (rid != bpp->relRids[oldIdx]) {
|
|
// need to find rid in relrids, and it is in there
|
|
oldIdx++;
|
|
oldRow.nextRow();
|
|
}
|
|
if (oldIdx != newIdx) {
|
|
bpp->relRids[newIdx] = rid;
|
|
// we use a memcpy here instead of copyRow() to avoid expanding the string table;
|
|
memcpy(newRow.getData(), oldRow.getData(), newRow.getSize());
|
|
}
|
|
oldIdx++;
|
|
oldRow.nextRow();
|
|
newRow.nextRow();
|
|
}
|
|
rg.setRowCount(outMsg->NVALS); // this gets rid of trailing rows, no need to set them to NULL
|
|
bpp->ridCount = outMsg->NVALS;
|
|
primMsg->NVALS = outMsg->NVALS;
|
|
}
|
|
|
|
void ColumnCommand::projectResultRG(RowGroup &rg, uint32_t pos)
|
|
{
|
|
uint32_t i, offset, gapSize;
|
|
uint8_t *msg8 = (uint8_t *) (outMsg + 1);
|
|
if (noVB) {
|
|
// outMsg has rids in this case
|
|
msg8 += 2;
|
|
gapSize = colType.colWidth + 2;
|
|
}
|
|
else
|
|
gapSize = colType.colWidth;
|
|
|
|
/* TODO: reoptimize these away */
|
|
rg.initRow(&r);
|
|
offset = r.getOffset(pos);
|
|
rowSize = r.getSize();
|
|
|
|
if ((primMsg->NVALS != outMsg->NVALS || outMsg->NVALS != bpp->ridCount) && (!noVB || bpp->sessionID & 0x80000000))
|
|
{
|
|
ostringstream os;
|
|
BRM::DBRM brm;
|
|
BRM::OID_t oid;
|
|
uint16_t dbroot;
|
|
uint32_t partNum;
|
|
uint16_t segNum;
|
|
uint32_t fbo;
|
|
brm.lookupLocal(lbid, 0, false, oid, dbroot, partNum, segNum, fbo);
|
|
|
|
os << __FILE__ << " error on projectResultRG for oid " << oid << " lbid " << lbid;
|
|
if (primMsg->NVALS != outMsg->NVALS )
|
|
os << ": input rids " << primMsg->NVALS;
|
|
else
|
|
os << ": ridcount " << bpp->ridCount;
|
|
os << ", output rids " << outMsg->NVALS;
|
|
/*
|
|
BRM::VSSData entry;
|
|
if (bpp->vssCache.find(lbid) != bpp->vssCache.end()) {
|
|
entry = bpp->vssCache[lbid];
|
|
if (entry.returnCode == 0)
|
|
os << " requested version " << entry.verID;
|
|
}
|
|
*/
|
|
os << endl;
|
|
if (bpp->sessionID & 0x80000000)
|
|
throw NeedToRestartJob(os.str());
|
|
else
|
|
throw PrimitiveColumnProjectResultExcept(os.str());
|
|
}
|
|
else if (primMsg->NVALS != outMsg->NVALS || outMsg->NVALS != bpp->ridCount)
|
|
removeRowsFromRowGroup(rg);
|
|
|
|
idbassert(primMsg->NVALS == outMsg->NVALS);
|
|
idbassert(outMsg->NVALS == bpp->ridCount);
|
|
rg.getRow(0, &r);
|
|
switch (colType.colWidth) {
|
|
case 1: {
|
|
for (i = 0; i < outMsg->NVALS; ++i, msg8 += gapSize) {
|
|
r.setUintField_offset<1>(*msg8, offset);
|
|
r.nextRow(rowSize);
|
|
}
|
|
break;
|
|
}
|
|
case 2: {
|
|
for (i = 0; i < outMsg->NVALS; ++i, msg8 += gapSize) {
|
|
r.setUintField_offset<2>(*((uint16_t *) msg8), offset);
|
|
r.nextRow(rowSize);
|
|
}
|
|
break;
|
|
}
|
|
case 4: {
|
|
for (i = 0; i < outMsg->NVALS; ++i, msg8 += gapSize) {
|
|
r.setUintField_offset<4>(*((uint32_t *) msg8), offset);
|
|
r.nextRow(rowSize);
|
|
}
|
|
break;
|
|
}
|
|
case 8: {
|
|
for (i = 0; i < outMsg->NVALS; ++i, msg8 += gapSize) {
|
|
r.setUintField_offset<8>(*((uint64_t *) msg8), offset);
|
|
r.nextRow(rowSize);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ColumnCommand::project()
|
|
{
|
|
/* bpp->ridCount == 0 would signify a scan operation */
|
|
if (bpp->ridCount == 0) {
|
|
*bpp->serialized << (uint32_t) 0;
|
|
blockCount += colType.colWidth;
|
|
return;
|
|
}
|
|
makeStepMsg();
|
|
issuePrimitive();
|
|
projectResult();
|
|
}
|
|
|
|
void ColumnCommand::projectIntoRowGroup(RowGroup &rg, uint32_t pos)
|
|
{
|
|
if (bpp->ridCount == 0) {
|
|
blockCount += colType.colWidth;
|
|
return;
|
|
}
|
|
makeStepMsg();
|
|
issuePrimitive();
|
|
projectResultRG(rg, pos);
|
|
}
|
|
|
|
void ColumnCommand::nextLBID()
|
|
{
|
|
lbid += colType.colWidth;
|
|
}
|
|
|
|
void ColumnCommand::duplicate(ColumnCommand *cc)
|
|
{
|
|
cc->_isScan = _isScan;
|
|
cc->traceFlags = traceFlags;
|
|
cc->filterString = filterString;
|
|
cc->colType.colDataType = colType.colDataType;
|
|
cc->colType.compressionType = colType.compressionType;
|
|
cc->colType.colWidth = colType.colWidth;
|
|
cc->BOP = BOP;
|
|
cc->filterCount = filterCount;
|
|
cc->fFilterFeeder = fFilterFeeder;
|
|
cc->parsedColumnFilter = parsedColumnFilter;
|
|
cc->suppressFilter = suppressFilter;
|
|
cc->lastLbid = lastLbid;
|
|
cc->r = r;
|
|
cc->rowSize = rowSize;
|
|
cc->Command::duplicate(this);
|
|
}
|
|
|
|
SCommand ColumnCommand::duplicate()
|
|
{
|
|
SCommand ret;
|
|
|
|
ret.reset(new ColumnCommand());
|
|
duplicate((ColumnCommand *) ret.get());
|
|
return ret;
|
|
}
|
|
|
|
bool ColumnCommand::operator==(const ColumnCommand &cc) const
|
|
{
|
|
if (_isScan != cc._isScan)
|
|
return false;
|
|
if (BOP != cc.BOP)
|
|
return false;
|
|
if (filterString != cc.filterString)
|
|
return false;
|
|
if (filterCount != cc.filterCount)
|
|
return false;
|
|
if (makeAbsRids != cc.makeAbsRids)
|
|
return false;
|
|
if (colType.colWidth != cc.colType.colWidth)
|
|
return false;
|
|
if (colType.colDataType != cc.colType.colDataType)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool ColumnCommand::operator!=(const ColumnCommand &cc) const
|
|
{
|
|
return !(*this == cc);
|
|
}
|
|
|
|
|
|
ColumnCommand & ColumnCommand::operator=(const ColumnCommand &c)
|
|
{
|
|
_isScan = c._isScan;
|
|
traceFlags = c.traceFlags;
|
|
filterString = c.filterString;
|
|
colType.colDataType = c.colType.colDataType;
|
|
colType.compressionType = c.colType.compressionType;
|
|
colType.colWidth = c.colType.colWidth;
|
|
BOP = c.BOP;
|
|
filterCount = c.filterCount;
|
|
fFilterFeeder = c.fFilterFeeder;
|
|
parsedColumnFilter = c.parsedColumnFilter;
|
|
suppressFilter = c.suppressFilter;
|
|
lastLbid = c.lastLbid;
|
|
return *this;
|
|
}
|
|
|
|
bool ColumnCommand::willPrefetch()
|
|
{
|
|
// if (blockCount > 0)
|
|
// cout << "load rate = " << ((double)loadCount)/((double)blockCount) << endl;
|
|
|
|
// if (!((double)loadCount)/((double)blockCount) > bpp->prefetchThreshold)
|
|
// cout << "suppressing prefetch\n";
|
|
|
|
//return false;
|
|
return (blockCount == 0 || ((double)loadCount)/((double)blockCount) >
|
|
bpp->prefetchThreshold);
|
|
}
|
|
|
|
void ColumnCommand::disableFilters()
|
|
{
|
|
suppressFilter = true;
|
|
prep(primMsg->OutputType, makeAbsRids);
|
|
}
|
|
|
|
void ColumnCommand::enableFilters()
|
|
{
|
|
suppressFilter = false;
|
|
prep(primMsg->OutputType, makeAbsRids);
|
|
}
|
|
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* Get the value that represents empty row
|
|
* PARAMETERS:
|
|
* dataType - data type
|
|
* width - data width in byte
|
|
* RETURN:
|
|
* emptyVal - the value of empty row
|
|
***********************************************************/
|
|
const uint64_t ColumnCommand::getEmptyRowValue( const execplan::CalpontSystemCatalog::ColDataType dataType, const int width ) const
|
|
{
|
|
uint64_t emptyVal = 0;
|
|
int offset;
|
|
|
|
offset = ( dataType == execplan::CalpontSystemCatalog::VARCHAR )? -1 : 0;
|
|
switch ( dataType )
|
|
{
|
|
case execplan::CalpontSystemCatalog::TINYINT :
|
|
emptyVal = joblist::TINYINTEMPTYROW;
|
|
break;
|
|
case execplan::CalpontSystemCatalog::SMALLINT:
|
|
emptyVal = joblist::SMALLINTEMPTYROW;
|
|
break;
|
|
case execplan::CalpontSystemCatalog::MEDINT :
|
|
case execplan::CalpontSystemCatalog::INT :
|
|
emptyVal = joblist::INTEMPTYROW;
|
|
break;
|
|
case execplan::CalpontSystemCatalog::BIGINT :
|
|
emptyVal = joblist::BIGINTEMPTYROW;
|
|
break;
|
|
|
|
case execplan::CalpontSystemCatalog::UTINYINT :
|
|
emptyVal = joblist::UTINYINTEMPTYROW;
|
|
break;
|
|
case execplan::CalpontSystemCatalog::USMALLINT:
|
|
emptyVal = joblist::USMALLINTEMPTYROW;
|
|
break;
|
|
case execplan::CalpontSystemCatalog::UMEDINT :
|
|
case execplan::CalpontSystemCatalog::UINT :
|
|
emptyVal = joblist::UINTEMPTYROW;
|
|
break;
|
|
case execplan::CalpontSystemCatalog::UBIGINT :
|
|
emptyVal = joblist::UBIGINTEMPTYROW;
|
|
break;
|
|
|
|
case execplan::CalpontSystemCatalog::FLOAT :
|
|
case execplan::CalpontSystemCatalog::UFLOAT :
|
|
emptyVal = joblist::FLOATEMPTYROW;
|
|
break;
|
|
case execplan::CalpontSystemCatalog::DOUBLE :
|
|
case execplan::CalpontSystemCatalog::UDOUBLE :
|
|
emptyVal = joblist::DOUBLEEMPTYROW;
|
|
break;
|
|
|
|
case execplan::CalpontSystemCatalog::DECIMAL :
|
|
case execplan::CalpontSystemCatalog::UDECIMAL :
|
|
if ( width <= 1 )
|
|
emptyVal = joblist::TINYINTEMPTYROW;
|
|
else if (width <= 2)
|
|
emptyVal = joblist::SMALLINTEMPTYROW;
|
|
else if ( width <= 4 )
|
|
emptyVal = joblist::INTEMPTYROW;
|
|
else
|
|
emptyVal = joblist::BIGINTEMPTYROW;
|
|
break;
|
|
|
|
case execplan::CalpontSystemCatalog::CHAR :
|
|
case execplan::CalpontSystemCatalog::VARCHAR :
|
|
case execplan::CalpontSystemCatalog::DATE :
|
|
case execplan::CalpontSystemCatalog::DATETIME :
|
|
case execplan::CalpontSystemCatalog::VARBINARY :
|
|
case execplan::CalpontSystemCatalog::BLOB :
|
|
case execplan::CalpontSystemCatalog::TEXT :
|
|
default:
|
|
emptyVal = joblist::CHAR1EMPTYROW;
|
|
if ( width == (2 + offset) )
|
|
emptyVal = joblist::CHAR2EMPTYROW;
|
|
else if ( width >= (3 + offset) && width <= ( 4 + offset ) )
|
|
emptyVal = joblist::CHAR4EMPTYROW;
|
|
else if ( width >= (5 + offset) )
|
|
emptyVal = joblist::CHAR8EMPTYROW;
|
|
break;
|
|
}
|
|
|
|
return emptyVal;
|
|
}
|
|
|
|
void ColumnCommand::getLBIDList(uint32_t loopCount, vector<int64_t> *lbids)
|
|
{
|
|
int64_t firstLBID = lbid, lastLBID = firstLBID + (loopCount * colType.colWidth) - 1, i;
|
|
|
|
for (i = firstLBID; i <= lastLBID; i++)
|
|
lbids->push_back(i);
|
|
}
|
|
|
|
const int64_t ColumnCommand::getLastLbid()
|
|
{
|
|
if (!_isScan)
|
|
return 0;
|
|
return lastLbid[bpp->dbRoot-1];
|
|
|
|
#if 0
|
|
/* PL - each dbroot has a different HWM; need to look up the local HWM on start */
|
|
BRM::DBRM dbrm;
|
|
BRM::OID_t oid;
|
|
uint32_t partNum;
|
|
uint16_t segNum;
|
|
uint32_t fbo;
|
|
|
|
dbrm.lookupLocal(primMsg->LBID, bpp->versionNum, false, oid, dbRoot, partNum, segNum, fbo);
|
|
gotDBRoot = true;
|
|
cout << "I think I'm on dbroot " << dbRoot << " lbid=" << primMsg->LBID << " ver=" << bpp->versionNum << endl;
|
|
dbRoot--;
|
|
return lastLbid[dbRoot];
|
|
#endif
|
|
}
|
|
|
|
}
|
|
// vim:ts=4 sw=4:
|
|
|