1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-12-20 01:42:27 +03:00

MCOL-523 Add UDAF and UDAnF SDK

This commit is contained in:
David Hall
2017-07-26 11:53:08 -05:00
parent bbad7882d2
commit a38b098f2a
72 changed files with 10264 additions and 4521 deletions

744
utils/rowgroup/rowaggregation.cpp Normal file → Executable file
View File

@@ -28,7 +28,7 @@
#include <sstream>
#include <stdexcept>
#include <limits>
#include <typeinfo>
#include "joblisttypes.h"
#include "resourcemanager.h"
#include "groupconcat.h"
@@ -459,7 +459,6 @@ inline void RowAggregation::updateFloatSum(float val1, float val2, int64_t col)
fRow.setFloatField(val1 + val2, col);
}
//------------------------------------------------------------------------------
// Verify if the column value is NULL
// row(in) - Row to be included in aggregation.
@@ -721,6 +720,41 @@ void RowAggregation::setJoinRowGroups(vector<RowGroup> *pSmallSideRG, RowGroup *
(*fSmallSideRGs)[i].initRow(&rowSmalls[i]);
}
//------------------------------------------------------------------------------
// For UDAF, we need to sometimes start a new context.
//
// This will be called any number of times by each of the batchprimitiveprocessor
// threads on the PM and by multple threads on the UM. It must remain
// thread safe.
//------------------------------------------------------------------------------
void RowAggregation::resetUDAF(uint64_t funcColID)
{
// Get the UDAF class pointer and store in the row definition object.
RowUDAFFunctionCol* rowUDAF = dynamic_cast<RowUDAFFunctionCol*>(fFunctionCols[funcColID].get());
// resetUDAF needs to be re-entrant. Since we're modifying the context object
// by creating a new userData, we need a local copy. The copy constructor
// doesn't copy userData.
mcsv1sdk::mcsv1Context rgContext(rowUDAF->fUDAFContext);
// Call the user reset for the group userData. Since, at this point,
// context's userData will be NULL, reset will generate a new one.
mcsv1sdk::mcsv1_UDAF::ReturnCode rc;
rc = rgContext.getFunction()->reset(&rgContext);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
rowUDAF->bInterrupted = true;
throw logging::QueryDataExcept(rgContext.getErrorMessage(), logging::aggregateFuncErr);
}
fRow.setUserDataStore(fRowGroupOut->getRGData()->getUserDataStore());
fRow.setUserData(rgContext,
rgContext.getUserDataSP(),
rgContext.getUserDataSize(),
rowUDAF->fAuxColumnIndex);
rgContext.setUserData(NULL); // Prevents calling deleteUserData on the context.
}
//------------------------------------------------------------------------------
// Initilalize the data members to meaningful values, setup the hashmap.
@@ -780,7 +814,7 @@ void RowAggregation::initialize()
//------------------------------------------------------------------------------
// Reset the working data to aggregate next logical block
//------------------------------------------------------------------------------
void RowAggregation::reset()
void RowAggregation::aggReset()
{
fTotalRowCount = 0;
fMaxTotalRowCount = AGG_ROWGROUP_SIZE;
@@ -798,15 +832,23 @@ void RowAggregation::reset()
delete fAggMapPtr;
fAggMapPtr = new RowAggMap_t(10, *fHasher, *fEq, *fAlloc);
}
fResultDataVec.clear();
fResultDataVec.push_back(fRowGroupOut->getRGData());
// For UDAF, reset the data
for (uint64_t i = 0; i < fFunctionCols.size(); i++)
{
if (fFunctionCols[i]->fAggFunction == ROWAGG_UDAF)
{
resetUDAF(i);
}
}
}
void RowAggregationUM::reset()
void RowAggregationUM::aggReset()
{
RowAggregation::reset();
RowAggregation::aggReset();
if (fKeyOnHeap)
{
@@ -843,6 +885,15 @@ void RowAggregationUM::aggregateRowWithRemap(Row& row)
attachGroupConcatAg();
inserted.first->second = RowPosition(fResultDataVec.size()-1, fRowGroupOut->getRowCount()-1);
// If there's UDAF involved, reset the user data.
for (uint64_t i = 0; i < fFunctionCols.size(); i++)
{
if (fFunctionCols[i]->fAggFunction == ROWAGG_UDAF)
{
resetUDAF(i);
}
}
// replace the key value with an equivalent copy, yes this is OK
const_cast<RowPosition &>((inserted.first->first)) = pos;
}
@@ -893,6 +944,16 @@ void RowAggregation::aggregateRow(Row& row)
// replace the key value with an equivalent copy, yes this is OK
const_cast<RowPosition &>(*(inserted.first)) =
RowPosition(fResultDataVec.size() - 1, fRowGroupOut->getRowCount() - 1);
// If there's UDAF involved, reset the user data.
for (uint64_t i = 0; i < fFunctionCols.size(); i++)
{
if (fFunctionCols[i]->fAggFunction == ROWAGG_UDAF)
{
resetUDAF(i);
}
}
}
else {
//fRow.setData(*(inserted.first));
@@ -1065,6 +1126,8 @@ void RowAggregation::makeAggFieldsNull(Row& row)
case execplan::CalpontSystemCatalog::CHAR:
case execplan::CalpontSystemCatalog::VARCHAR:
case execplan::CalpontSystemCatalog::TEXT:
case execplan::CalpontSystemCatalog::VARBINARY:
case execplan::CalpontSystemCatalog::BLOB:
{
int colWidth = fRowGroupOut->getColumnWidth(colOut);
if (colWidth <= 8)
@@ -1386,7 +1449,7 @@ void RowAggregation::serialize(messageqcpp::ByteStream& bs) const
bs << functionCount;
for (uint64_t i = 0; i < functionCount; i++)
bs << *(fFunctionCols[i].get());
fFunctionCols[i]->serialize(bs);
}
@@ -1415,9 +1478,18 @@ void RowAggregation::deserialize(messageqcpp::ByteStream& bs)
for (uint64_t i = 0; i < functionCount; i++)
{
SP_ROWAGG_FUNC_t funct(
new RowAggFunctionCol(ROWAGG_FUNCT_UNDEFINE, ROWAGG_FUNCT_UNDEFINE, 0, 0));
bs >> *(funct.get());
uint8_t funcType;
bs.peek(funcType);
SP_ROWAGG_FUNC_t funct;
if (funcType == ROWAGG_UDAF)
{
funct.reset(new RowUDAFFunctionCol(0, 0));
}
else
{
funct.reset(new RowAggFunctionCol(ROWAGG_FUNCT_UNDEFINE, ROWAGG_FUNCT_UNDEFINE, 0, 0));
}
funct->deserialize(bs);
fFunctionCols.push_back(funct);
}
}
@@ -1477,6 +1549,20 @@ void RowAggregation::updateEntry(const Row& rowIn)
case ROWAGG_GROUP_CONCAT:
break;
case ROWAGG_UDAF:
{
RowUDAFFunctionCol* rowUDAF = dynamic_cast<RowUDAFFunctionCol*>(fFunctionCols[i].get());
if (rowUDAF)
{
doUDAF(rowIn, colIn, colOut, colOut + 1, rowUDAF);
}
else
{
throw logic_error("(3)A UDAF function is called but there's no RowUDAFFunctionCol");
}
break;
}
default:
{
std::ostringstream errmsg;
@@ -1729,6 +1815,113 @@ void RowAggregation::doStatistics(const Row& rowIn, int64_t colIn, int64_t colOu
fRow.setLongDoubleField(fRow.getLongDoubleField(colAux+1) + valIn*valIn, colAux+1);
}
void RowAggregation::doUDAF(const Row& rowIn, int64_t colIn, int64_t colOut, int64_t colAux,
RowUDAFFunctionCol* rowUDAF)
{
std::vector<mcsv1sdk::ColumnDatum> valsIn;
execplan::CalpontSystemCatalog::ColDataType colDataType = fRowGroupIn.getColTypes()[colIn];
std::vector<uint32_t> dataFlags;
// Get the context for this rowGroup. Make a copy so we're thread safe.
mcsv1sdk::mcsv1Context rgContext(rowUDAF->fUDAFContext);
// Turn on NULL flags
std::vector<uint32_t> flags;
uint32_t flag = 0;
if (isNull(&fRowGroupIn, rowIn, colIn) == true)
{
if (rgContext.getRunFlag(mcsv1sdk::UDAF_IGNORE_NULLS))
{
return;
}
flag |= mcsv1sdk::PARAM_IS_NULL;
}
flags.push_back(flag);
rgContext.setDataFlags(&flags);
mcsv1sdk::ColumnDatum datum;
switch (colDataType)
{
case execplan::CalpontSystemCatalog::TINYINT:
case execplan::CalpontSystemCatalog::SMALLINT:
case execplan::CalpontSystemCatalog::MEDINT:
case execplan::CalpontSystemCatalog::INT:
case execplan::CalpontSystemCatalog::BIGINT:
case execplan::CalpontSystemCatalog::DECIMAL:
case execplan::CalpontSystemCatalog::UDECIMAL:
{
datum.dataType = execplan::CalpontSystemCatalog::BIGINT;
datum.columnData = rowIn.getIntField(colIn);
datum.scale = fRowGroupIn.getScale()[colIn];
datum.precision = fRowGroupIn.getPrecision()[colIn];
break;
}
case execplan::CalpontSystemCatalog::UTINYINT:
case execplan::CalpontSystemCatalog::USMALLINT:
case execplan::CalpontSystemCatalog::UMEDINT:
case execplan::CalpontSystemCatalog::UINT:
case execplan::CalpontSystemCatalog::UBIGINT:
{
datum.dataType = execplan::CalpontSystemCatalog::UBIGINT;
datum.columnData = rowIn.getUintField(colIn);
break;
}
case execplan::CalpontSystemCatalog::DOUBLE:
case execplan::CalpontSystemCatalog::UDOUBLE:
{
datum.dataType = execplan::CalpontSystemCatalog::DOUBLE;
datum.columnData = rowIn.getDoubleField(colIn);
break;
}
case execplan::CalpontSystemCatalog::FLOAT:
case execplan::CalpontSystemCatalog::UFLOAT:
{
datum.dataType = execplan::CalpontSystemCatalog::FLOAT;
datum.columnData = rowIn.getFloatField(colIn);
break;
}
case execplan::CalpontSystemCatalog::DATE:
case execplan::CalpontSystemCatalog::DATETIME:
{
datum.dataType = execplan::CalpontSystemCatalog::UBIGINT;
datum.columnData = rowIn.getUintField(colIn);
break;
}
case execplan::CalpontSystemCatalog::CHAR:
case execplan::CalpontSystemCatalog::VARCHAR:
case execplan::CalpontSystemCatalog::TEXT:
case execplan::CalpontSystemCatalog::VARBINARY:
case execplan::CalpontSystemCatalog::CLOB:
case execplan::CalpontSystemCatalog::BLOB:
{
datum.dataType = colDataType;
datum.columnData = rowIn.getStringField(colIn);
break;
}
default:
{
std::ostringstream errmsg;
errmsg << "RowAggregation " << rgContext.getName() <<
": No logic for data type: " << colDataType;
throw logging::QueryDataExcept(errmsg.str(), logging::aggregateFuncErr);
break;
}
}
valsIn.push_back(datum);
// The intermediate values are stored in userData referenced by colAux.
rgContext.setUserData(fRow.getUserData(colAux));
mcsv1sdk::mcsv1_UDAF::ReturnCode rc;
rc = rgContext.getFunction()->nextValue(&rgContext, valsIn);
rgContext.setUserData(NULL);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
rowUDAF->bInterrupted = true;
throw logging::QueryDataExcept(rgContext.getErrorMessage(), logging::aggregateFuncErr);
}
}
//------------------------------------------------------------------------------
// Allocate a new data array for the output RowGroup
@@ -1781,7 +1974,6 @@ void RowAggregation::loadEmptySet(messageqcpp::ByteStream& bs)
fEmptyRowGroup.serializeRGData(bs);
}
//------------------------------------------------------------------------------
// Row Aggregation constructor used on UM
// For one-phase case, from projected RG to final aggregated RG
@@ -1790,10 +1982,11 @@ RowAggregationUM::RowAggregationUM(const vector<SP_ROWAGG_GRPBY_t>& rowAggGroupB
const vector<SP_ROWAGG_FUNC_t>& rowAggFunctionCols,
joblist::ResourceManager *r, boost::shared_ptr<int64_t> sessionLimit) :
RowAggregation(rowAggGroupByCols, rowAggFunctionCols), fHasAvg(false), fKeyOnHeap(false),
fHasStatsFunc(false), fTotalMemUsage(0), fRm(r), fSessionMemLimit(sessionLimit),
fLastMemUsage(0), fNextRGIndex(0)
fHasStatsFunc(false), fHasUDAF(false),fTotalMemUsage(0), fRm(r),
fSessionMemLimit(sessionLimit), fLastMemUsage(0), fNextRGIndex(0)
{
// Check if there are any avg functions.
// Check if there are any avg, stats or UDAF functions.
// These flags are used in finalize.
for (uint64_t i = 0; i < fFunctionCols.size(); i++)
{
if (fFunctionCols[i]->fAggFunction == ROWAGG_AVG ||
@@ -1801,6 +1994,8 @@ RowAggregationUM::RowAggregationUM(const vector<SP_ROWAGG_GRPBY_t>& rowAggGroupB
fHasAvg = true;
else if (fFunctionCols[i]->fAggFunction == ROWAGG_STATS)
fHasStatsFunc = true;
else if (fFunctionCols[i]->fAggFunction == ROWAGG_UDAF)
fHasUDAF = true;
}
// Check if all groupby column selected
@@ -1904,6 +2099,11 @@ void RowAggregationUM::finalize()
calculateStatisticsFunctions();
}
if (fHasUDAF)
{
calculateUDAFColumns();
}
if (fGroupConcat.size() > 0)
setGroupConcatString();
@@ -1950,6 +2150,7 @@ void RowAggregationUM::updateEntry(const Row& rowIn)
{
int64_t colIn = fFunctionCols[i]->fInputColumnIndex;
int64_t colOut = fFunctionCols[i]->fOutputColumnIndex;
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
switch (fFunctionCols[i]->fAggFunction)
{
@@ -1971,14 +2172,12 @@ void RowAggregationUM::updateEntry(const Row& rowIn)
// The sum and count on UM may not be put next to each other:
// use colOut to store the sum;
// use colAux to store the count.
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
doAvg(rowIn, colIn, colOut, colAux);
break;
}
case ROWAGG_STATS:
{
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
doStatistics(rowIn, colIn, colOut, colAux);
break;
}
@@ -2004,6 +2203,20 @@ void RowAggregationUM::updateEntry(const Row& rowIn)
case ROWAGG_CONSTANT:
break;
case ROWAGG_UDAF:
{
RowUDAFFunctionCol* rowUDAF = dynamic_cast<RowUDAFFunctionCol*>(fFunctionCols[i].get());
if (rowUDAF)
{
doUDAF(rowIn, colIn, colOut, colAux, rowUDAF);
}
else
{
throw logic_error("(5)A UDAF function is called but there's no RowUDAFFunctionCol");
}
break;
}
default:
{
// need a exception to show the value
@@ -2143,6 +2356,251 @@ void RowAggregationUM::calculateAvgColumns()
}
}
// Sets the value from valOut into column colOut, performing any conversions.
void RowAggregationUM::SetUDAFValue(static_any::any& valOut, int64_t colOut)
{
static const static_any::any& charTypeId = (char)1;
static const static_any::any& scharTypeId = (signed char)1;
static const static_any::any& shortTypeId = (short)1;
static const static_any::any& intTypeId = (int)1;
static const static_any::any& longTypeId = (long)1;
static const static_any::any& llTypeId = (long long)1;
static const static_any::any& ucharTypeId = (unsigned char)1;
static const static_any::any& ushortTypeId = (unsigned short)1;
static const static_any::any& uintTypeId = (unsigned int)1;
static const static_any::any& ulongTypeId = (unsigned long)1;
static const static_any::any& ullTypeId = (unsigned long long)1;
static const static_any::any& floatTypeId = (float)1;
static const static_any::any& doubleTypeId = (double)1;
static const std::string typeStr("");
static const static_any::any& strTypeId = typeStr;
execplan::CalpontSystemCatalog::ColDataType colDataType = fRowGroupOut->getColTypes()[colOut];
if (valOut.empty())
{
// Fields are initialized to NULL, which is what we want for empty;
return;
}
// This may seem a bit convoluted. Users shouldn't return a type
// that they didn't set in mcsv1_UDAF::init(), but this
// handles whatever return type is given and casts
// it to whatever they said to return.
int64_t intOut = 0;
uint64_t uintOut = 0;
float floatOut = 0.0;
double doubleOut = 0.0;
ostringstream oss;
std::string strOut;
if (valOut.compatible(charTypeId))
{
uintOut = intOut = valOut.cast<char>();
floatOut = intOut;
oss << intOut;
}
else if (valOut.compatible(scharTypeId))
{
uintOut = intOut = valOut.cast<signed char>();
floatOut = intOut;
oss << intOut;
}
else if (valOut.compatible(shortTypeId))
{
uintOut = intOut = valOut.cast<short>();
floatOut = intOut;
oss << intOut;
}
else if (valOut.compatible(intTypeId))
{
uintOut = intOut = valOut.cast<int>();
floatOut = intOut;
oss << intOut;
}
else if (valOut.compatible(longTypeId))
{
uintOut = intOut = valOut.cast<long>();
floatOut = intOut;
oss << intOut;
}
else if (valOut.compatible(llTypeId))
{
uintOut = intOut = valOut.cast<long long>();
floatOut = intOut;
oss << intOut;
}
else if (valOut.compatible(ucharTypeId))
{
intOut = uintOut = valOut.cast<unsigned char>();
floatOut = uintOut;
oss << uintOut;
}
else if (valOut.compatible(ushortTypeId))
{
intOut = uintOut = valOut.cast<unsigned short>();
floatOut = uintOut;
oss << uintOut;
}
else if (valOut.compatible(uintTypeId))
{
intOut = uintOut = valOut.cast<unsigned int>();
floatOut = uintOut;
oss << uintOut;
}
else if (valOut.compatible(ulongTypeId))
{
intOut = uintOut = valOut.cast<unsigned long>();
floatOut = uintOut;
oss << uintOut;
}
else if (valOut.compatible(ullTypeId))
{
intOut = uintOut = valOut.cast<unsigned long long>();
floatOut = uintOut;
oss << uintOut;
}
else if (valOut.compatible(floatTypeId))
{
floatOut = valOut.cast<float>();
doubleOut = floatOut;
intOut = uintOut = floatOut;
oss << floatOut;
}
else if (valOut.compatible(doubleTypeId))
{
doubleOut = valOut.cast<double>();
floatOut = (float)doubleOut;
uintOut = (uint64_t)doubleOut;
intOut = (int64_t)doubleOut;
oss << doubleOut;
}
if (valOut.compatible(strTypeId))
{
std::string strOut = valOut.cast<std::string>();
// Convert the string to numeric type, just in case.
intOut = atol(strOut.c_str());
uintOut = strtoul(strOut.c_str(), NULL, 10);
doubleOut = strtod(strOut.c_str(), NULL);
floatOut = (float)doubleOut;
}
else
{
strOut = oss.str();
}
switch (colDataType)
{
case execplan::CalpontSystemCatalog::BIT:
case execplan::CalpontSystemCatalog::TINYINT:
fRow.setIntField<1>(intOut, colOut);
break;
case execplan::CalpontSystemCatalog::SMALLINT:
case execplan::CalpontSystemCatalog::MEDINT:
fRow.setIntField<2>(intOut, colOut);
break;
case execplan::CalpontSystemCatalog::INT:
fRow.setIntField<4>(intOut, colOut);
break;
case execplan::CalpontSystemCatalog::BIGINT:
case execplan::CalpontSystemCatalog::DECIMAL:
case execplan::CalpontSystemCatalog::UDECIMAL:
fRow.setIntField<8>(intOut, colOut);
break;
case execplan::CalpontSystemCatalog::UTINYINT:
fRow.setUintField<1>(uintOut, colOut);
break;
case execplan::CalpontSystemCatalog::USMALLINT:
case execplan::CalpontSystemCatalog::UMEDINT:
fRow.setUintField<2>(uintOut, colOut);
break;
case execplan::CalpontSystemCatalog::UINT:
fRow.setUintField<4>(uintOut, colOut);
break;
case execplan::CalpontSystemCatalog::UBIGINT:
fRow.setUintField<8>(uintOut, colOut);
break;
case execplan::CalpontSystemCatalog::DATE:
case execplan::CalpontSystemCatalog::DATETIME:
fRow.setUintField<8>(uintOut, colOut);
break;
case execplan::CalpontSystemCatalog::FLOAT:
case execplan::CalpontSystemCatalog::UFLOAT:
fRow.setFloatField(floatOut, colOut);
break;
case execplan::CalpontSystemCatalog::DOUBLE:
case execplan::CalpontSystemCatalog::UDOUBLE:
fRow.setDoubleField(doubleOut, colOut);
break;
case execplan::CalpontSystemCatalog::CHAR:
case execplan::CalpontSystemCatalog::VARCHAR:
case execplan::CalpontSystemCatalog::TEXT:
fRow.setStringField(strOut, colOut);
break;
case execplan::CalpontSystemCatalog::VARBINARY:
case execplan::CalpontSystemCatalog::CLOB:
case execplan::CalpontSystemCatalog::BLOB:
fRow.setVarBinaryField(strOut, colOut);
break;
default:
{
std::ostringstream errmsg;
errmsg << "RowAggregation: No logic for data type: " << colDataType;
throw logging::QueryDataExcept(errmsg.str(), logging::aggregateFuncErr);
break;
}
}
}
//------------------------------------------------------------------------------
//
// For each rowgroup, calculate the final value.
//------------------------------------------------------------------------------
void RowAggregationUM::calculateUDAFColumns()
{
RowUDAFFunctionCol* rowUDAF = NULL;
static_any::any valOut;
for (uint64_t i = 0; i < fFunctionCols.size(); i++)
{
if (fFunctionCols[i]->fAggFunction != ROWAGG_UDAF)
continue;
rowUDAF = dynamic_cast<RowUDAFFunctionCol*>(fFunctionCols[i].get());
mcsv1sdk::mcsv1Context rgContext(rowUDAF->fUDAFContext);
int64_t colOut = rowUDAF->fOutputColumnIndex;
int64_t colAux = rowUDAF->fAuxColumnIndex;
// At this point, each row is an aggregated GROUP BY.
for (uint64_t j = 0; j < fRowGroupOut->getRowCount(); j++)
{
// Get the user data from the row and evaluate.
fRowGroupOut->getRow(j, &fRow);
// Turn the NULL flag off. We can't know NULL at this point
rgContext.setDataFlags(NULL);
// The intermediate values are stored in colAux.
rgContext.setUserData(fRow.getUserData(colAux));
// Call the UDAF evaluate function
mcsv1sdk::mcsv1_UDAF::ReturnCode rc;
rc = rgContext.getFunction()->evaluate(&rgContext, valOut);
rgContext.setUserData(NULL);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
rowUDAF->bInterrupted = true;
throw logging::QueryDataExcept(rgContext.getErrorMessage(), logging::aggregateFuncErr);
}
// Set the returned value into the output row
SetUDAFValue(valOut, colOut);
}
rgContext.setUserData(NULL);
}
}
//------------------------------------------------------------------------------
// After all PM rowgroups received, calculate the statistics.
@@ -2222,7 +2680,6 @@ void RowAggregationUM::calculateStatisticsFunctions()
}
}
//------------------------------------------------------------------------------
// Fix the duplicate function columns -- same function same column id repeated
//------------------------------------------------------------------------------
@@ -2248,7 +2705,6 @@ void RowAggregationUM::fixDuplicates(RowAggFunctionType funct)
}
}
//------------------------------------------------------------------------------
// Evaluate the functions and expressions
//------------------------------------------------------------------------------
@@ -2262,7 +2718,6 @@ void RowAggregationUM::evaluateExpression()
}
}
//------------------------------------------------------------------------------
// Calculate the aggregate(constant) columns
//------------------------------------------------------------------------------
@@ -2395,6 +2850,58 @@ void RowAggregationUM::doNullConstantAggregate(const ConstantAggData& aggData, u
}
break;
case ROWAGG_UDAF:
{
int64_t rowCnt = 0;
// For a NULL constant, call nextValue with NULL and then evaluate.
bool bInterrupted = false;
mcsv1sdk::mcsv1Context context;
context.setRowCnt(rowCnt);
context.setInterrupted(bInterrupted);
context.createUserData();
mcsv1sdk::mcsv1_UDAF::ReturnCode rc;
std::vector<mcsv1sdk::ColumnDatum> valsIn;
// Call a reset, then nextValue, then execute. This will evaluate
// the UDAF for the constant.
rc = context.getFunction()->reset(&context);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
context.setInterrupted(true);
throw logging::QueryDataExcept(context.getErrorMessage(), logging::aggregateFuncErr);
}
// Turn the NULL and CONSTANT flags on.
std::vector<uint32_t> flags;
uint32_t flag = mcsv1sdk::PARAM_IS_NULL | mcsv1sdk::PARAM_IS_CONSTANT;
flags.push_back(flag);
context.setDataFlags(&flags);
// Create a dummy datum
mcsv1sdk::ColumnDatum datum;
datum.dataType = execplan::CalpontSystemCatalog::BIGINT;
datum.columnData = 0;
valsIn.push_back(datum);
rc = context.getFunction()->nextValue(&context, valsIn);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
context.setInterrupted(true);
throw logging::QueryDataExcept(context.getErrorMessage(), logging::aggregateFuncErr);
}
static_any::any valOut;
rc = context.getFunction()->evaluate(&context, valOut);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
context.setInterrupted(true);
throw logging::QueryDataExcept(context.getErrorMessage(), logging::aggregateFuncErr);
}
// Set the returned value into the output row
SetUDAFValue(valOut, colOut);
context.setDataFlags(NULL);
}
break;
default:
{
fRow.setStringField("", colOut);
@@ -2674,6 +3181,133 @@ void RowAggregationUM::doNotNullConstantAggregate(const ConstantAggData& aggData
}
break;
case ROWAGG_UDAF:
{
int64_t rowCnt = 0;
bool bInterrupted = false;
mcsv1sdk::mcsv1Context context;
context.setRowCnt(rowCnt);
context.setInterrupted(bInterrupted);
// Try the complex data initiation. If not implemented, use the simple,
context.createUserData();
mcsv1sdk::mcsv1_UDAF::ReturnCode rc;
std::vector<mcsv1sdk::ColumnDatum> valsIn;
// Call a reset, then nextValue, then execute. This will evaluate
// the UDAF for the constant.
rc = context.getFunction()->reset(&context);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
context.setInterrupted(true);
throw logging::QueryDataExcept(context.getErrorMessage(), logging::aggregateFuncErr);
}
// Turn the CONSTANT flags on.
std::vector<uint32_t> flags;
uint32_t flag = mcsv1sdk::PARAM_IS_CONSTANT;
flags.push_back(flag);
context.setDataFlags(&flags);
// Create a datum item for sending to UDAF
mcsv1sdk::ColumnDatum datum;
datum.dataType = (CalpontSystemCatalog::ColDataType)colDataType;
switch (colDataType)
{
case execplan::CalpontSystemCatalog::TINYINT:
case execplan::CalpontSystemCatalog::SMALLINT:
case execplan::CalpontSystemCatalog::MEDINT:
case execplan::CalpontSystemCatalog::INT:
case execplan::CalpontSystemCatalog::BIGINT:
{
datum.columnData = strtol(aggData.fConstValue.c_str(), 0, 10);
}
break;
case execplan::CalpontSystemCatalog::UTINYINT:
case execplan::CalpontSystemCatalog::USMALLINT:
case execplan::CalpontSystemCatalog::UMEDINT:
case execplan::CalpontSystemCatalog::UINT:
case execplan::CalpontSystemCatalog::UBIGINT:
{
datum.columnData = strtoul(aggData.fConstValue.c_str(), 0, 10);
}
break;
case execplan::CalpontSystemCatalog::DECIMAL:
case execplan::CalpontSystemCatalog::UDECIMAL:
{
double dbl = strtod(aggData.fConstValue.c_str(), 0);
double scale = pow(10.0, (double) fRowGroupOut->getScale()[i]);
datum.columnData = (int64_t)(scale*dbl);
datum.scale = scale;
datum.precision = fRowGroupOut->getPrecision()[i];
}
break;
case execplan::CalpontSystemCatalog::DOUBLE:
case execplan::CalpontSystemCatalog::UDOUBLE:
{
datum.columnData = strtod(aggData.fConstValue.c_str(), 0);
}
break;
case execplan::CalpontSystemCatalog::FLOAT:
case execplan::CalpontSystemCatalog::UFLOAT:
{
#ifdef _MSC_VER
datum.columnData = strtod(aggData.fConstValue.c_str(), 0);
#else
datum.columnData = strtof(aggData.fConstValue.c_str(), 0);
#endif
}
break;
case execplan::CalpontSystemCatalog::DATE:
{
datum.columnData = DataConvert::stringToDate(aggData.fConstValue);
}
break;
case execplan::CalpontSystemCatalog::DATETIME:
{
datum.columnData = DataConvert::stringToDatetime(aggData.fConstValue);
}
break;
case execplan::CalpontSystemCatalog::CHAR:
case execplan::CalpontSystemCatalog::VARCHAR:
case execplan::CalpontSystemCatalog::TEXT:
case execplan::CalpontSystemCatalog::VARBINARY:
case execplan::CalpontSystemCatalog::BLOB:
default:
{
datum.columnData = aggData.fConstValue;
}
break;
}
valsIn.push_back(datum);
rc = context.getFunction()->nextValue(&context, valsIn);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
context.setInterrupted(true);
throw logging::QueryDataExcept(context.getErrorMessage(), logging::aggregateFuncErr);
}
static_any::any valOut;
rc = context.getFunction()->evaluate(&context, valOut);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
context.setInterrupted(true);
throw logging::QueryDataExcept(context.getErrorMessage(), logging::aggregateFuncErr);
}
// Set the returned value into the output row
SetUDAFValue(valOut, colOut);
context.setDataFlags(NULL);
}
break;
default:
{
fRow.setStringField(aggData.fConstValue, colOut);
@@ -2823,6 +3457,7 @@ void RowAggregationUMP2::updateEntry(const Row& rowIn)
{
int64_t colIn = fFunctionCols[i]->fInputColumnIndex;
int64_t colOut = fFunctionCols[i]->fOutputColumnIndex;
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
switch (fFunctionCols[i]->fAggFunction)
{
@@ -2845,14 +3480,12 @@ void RowAggregationUMP2::updateEntry(const Row& rowIn)
// The sum and count on UM may not be put next to each other:
// use colOut to store the sum;
// use colAux to store the count.
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
doAvg(rowIn, colIn, colOut, colAux);
break;
}
case ROWAGG_STATS:
{
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
doStatistics(rowIn, colIn, colOut, colAux);
break;
}
@@ -2878,6 +3511,20 @@ void RowAggregationUMP2::updateEntry(const Row& rowIn)
case ROWAGG_CONSTANT:
break;
case ROWAGG_UDAF:
{
RowUDAFFunctionCol* rowUDAF = dynamic_cast<RowUDAFFunctionCol*>(fFunctionCols[i].get());
if (rowUDAF)
{
doUDAF(rowIn, colIn, colOut, colAux, rowUDAF);
}
else
{
throw logic_error("(6)A UDAF function is called but there's no RowUDAFFunctionCol");
}
break;
}
default:
{
std::ostringstream errmsg;
@@ -3050,6 +3697,43 @@ void RowAggregationUMP2::doBitOp(const Row& rowIn, int64_t colIn, int64_t colOut
fRow.setUintField(valIn ^ valOut, colOut);
}
//------------------------------------------------------------------------------
// Subaggregate the UDAF. This calls subaggregate for each partially
// aggregated row returned by the PM
// rowIn(in) - Row to be included in aggregation.
// colIn(in) - column in the input row group
// colOut(in) - column in the output row group
// colAux(in) - Where the UDAF userdata resides
// rowUDAF(in) - pointer to the RowUDAFFunctionCol for this UDAF instance
//------------------------------------------------------------------------------
void RowAggregationUMP2::doUDAF(const Row& rowIn, int64_t colIn, int64_t colOut, int64_t colAux,
RowUDAFFunctionCol* rowUDAF)
{
static_any::any valOut;
mcsv1sdk::mcsv1Context rgContext(rowUDAF->fUDAFContext);
// Turn on NULL flags
std::vector<uint32_t> flags;
uint32_t flag = 0;
if (isNull(&fRowGroupIn, rowIn, colIn) == true)
flag |= mcsv1sdk::PARAM_IS_NULL;
flags.push_back(flag);
rgContext.setDataFlags(&flags);
// The intermediate values are stored in colAux.
rgContext.setUserData(fRow.getUserData(colAux));
// Call the UDAF subEvaluate method
mcsv1sdk::mcsv1_UDAF::ReturnCode rc;
rc = rgContext.getFunction()->subEvaluate(&rgContext, rowIn.getUserData(colIn+1).get());
rgContext.setUserData(NULL);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
rowUDAF->bInterrupted = true;
throw logging::QueryDataExcept(rgContext.getErrorMessage(), logging::aggregateFuncErr);
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
@@ -3163,6 +3847,7 @@ void RowAggregationDistinct::updateEntry(const Row& rowIn)
{
int64_t colIn = fFunctionCols[i]->fInputColumnIndex;
int64_t colOut = fFunctionCols[i]->fOutputColumnIndex;
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
switch (fFunctionCols[i]->fAggFunction)
{
@@ -3192,7 +3877,6 @@ void RowAggregationDistinct::updateEntry(const Row& rowIn)
// The sum and count on UM may not be put next to each other:
// use colOut to store the sum;
// use colAux to store the count.
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
doAvg(rowIn, colIn, colOut, colAux);
break;
}
@@ -3202,14 +3886,12 @@ void RowAggregationDistinct::updateEntry(const Row& rowIn)
// The sum and count on UM may not be put next to each other:
// use colOut to store the sum;
// use colAux to store the count.
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
RowAggregation::doAvg(rowIn, colIn, colOut, colAux);
break;
}
case ROWAGG_STATS:
{
int64_t colAux = fFunctionCols[i]->fAuxColumnIndex;
doStatistics(rowIn, colIn, colOut, colAux);
break;
}
@@ -3235,6 +3917,20 @@ void RowAggregationDistinct::updateEntry(const Row& rowIn)
case ROWAGG_CONSTANT:
break;
case ROWAGG_UDAF:
{
RowUDAFFunctionCol* rowUDAF = dynamic_cast<RowUDAFFunctionCol*>(fFunctionCols[i].get());
if (rowUDAF)
{
doUDAF(rowIn, colIn, colOut, colAux, rowUDAF);
}
else
{
throw logic_error("(7)A UDAF function is called but there's no RowUDAFFunctionCol");
}
break;
}
default:
{
std::ostringstream errmsg;

104
utils/rowgroup/rowaggregation.h Normal file → Executable file
View File

@@ -49,6 +49,7 @@
#include "hasher.h"
#include "stlpoolallocator.h"
#include "returnedcolumn.h"
#include "mcsv1_udaf.h"
// To do: move code that depends on joblist to a proper subsystem.
namespace joblist
@@ -64,6 +65,7 @@ struct RowPosition
{
uint64_t group:48;
uint64_t row:16;
static const uint64_t MSB = 0x800000000000ULL; //48th bit is set
inline RowPosition(uint64_t g, uint64_t r) : group(g), row(r) { }
inline RowPosition() { }
@@ -105,6 +107,9 @@ enum RowAggFunctionType
// Constant
ROWAGG_CONSTANT,
// User Defined Aggregate Function
ROWAGG_UDAF,
// internal function type to avoid duplicate the work
// handling ROWAGG_COUNT_NO_OP, ROWAGG_DUP_FUNCT and ROWAGG_DUP_AVG is a little different
// ROWAGG_COUNT_NO_OP : count done by AVG, no need to copy
@@ -169,7 +174,10 @@ struct RowAggFunctionCol
int32_t inputColIndex, int32_t outputColIndex, int32_t auxColIndex = -1) :
fAggFunction(aggFunction), fStatsFunction(stats), fInputColumnIndex(inputColIndex),
fOutputColumnIndex(outputColIndex), fAuxColumnIndex(auxColIndex) {}
~RowAggFunctionCol() {}
virtual ~RowAggFunctionCol() {}
virtual void serialize(messageqcpp::ByteStream& bs) const;
virtual void deserialize(messageqcpp::ByteStream& bs);
RowAggFunctionType fAggFunction; // aggregate function
// statistics function stores ROWAGG_STATS in fAggFunction and real function in fStatsFunction
@@ -178,24 +186,86 @@ struct RowAggFunctionCol
uint32_t fInputColumnIndex;
uint32_t fOutputColumnIndex;
// fAuxColumnIndex is used in 3 cases:
// fAuxColumnIndex is used in 4 cases:
// 1. for AVG - point to the count column, the fInputColumnIndex is for sum
// 2. for statistics function - point to sum(x), +1 is sum(x**2)
// 3. for duplicate - point to the real aggretate column to be copied from
// 3. for UDAF - contain the context user data as binary
// 4. for duplicate - point to the real aggretate column to be copied from
// Set only on UM, the fAuxColumnIndex is defaulted to fOutputColumnIndex+1 on PM.
uint32_t fAuxColumnIndex;
};
inline messageqcpp::ByteStream& operator<<(messageqcpp::ByteStream& b, RowAggFunctionCol& o)
{ return (b << (uint8_t)o.fAggFunction << o.fInputColumnIndex << o.fOutputColumnIndex); }
inline messageqcpp::ByteStream& operator>>(messageqcpp::ByteStream& b, RowAggFunctionCol& o)
{ return (b >> (uint8_t&)o.fAggFunction >> o.fInputColumnIndex >> o.fOutputColumnIndex); }
struct RowUDAFFunctionCol : public RowAggFunctionCol
{
RowUDAFFunctionCol(mcsv1sdk::mcsv1Context& context, int32_t inputColIndex,
int32_t outputColIndex, int32_t auxColIndex = -1) :
RowAggFunctionCol(ROWAGG_UDAF, ROWAGG_FUNCT_UNDEFINE,
inputColIndex, outputColIndex, auxColIndex),
fUDAFContext(context), bInterrupted(false)
{
fUDAFContext.setInterrupted(&bInterrupted);
}
RowUDAFFunctionCol(int32_t inputColIndex,
int32_t outputColIndex, int32_t auxColIndex = -1) :
RowAggFunctionCol(ROWAGG_UDAF, ROWAGG_FUNCT_UNDEFINE,
inputColIndex, outputColIndex, auxColIndex),
bInterrupted(false)
{}
RowUDAFFunctionCol(const RowUDAFFunctionCol& rhs) : RowAggFunctionCol(ROWAGG_UDAF, ROWAGG_FUNCT_UNDEFINE,
rhs.fInputColumnIndex, rhs.fOutputColumnIndex, rhs.fAuxColumnIndex), fUDAFContext(rhs.fUDAFContext)
{}
virtual ~RowUDAFFunctionCol() {}
virtual void serialize(messageqcpp::ByteStream& bs) const;
virtual void deserialize(messageqcpp::ByteStream& bs);
mcsv1sdk::mcsv1Context fUDAFContext; // The UDAF context
bool bInterrupted; // Shared by all the threads
};
inline void RowAggFunctionCol::serialize(messageqcpp::ByteStream& bs) const
{
bs << (uint8_t)fAggFunction;
bs << fInputColumnIndex;
bs << fOutputColumnIndex;
}
inline void RowAggFunctionCol::deserialize(messageqcpp::ByteStream& bs)
{
bs >> (uint8_t&)fAggFunction;
bs >> fInputColumnIndex;
bs >> fOutputColumnIndex;
}
inline void RowUDAFFunctionCol::serialize(messageqcpp::ByteStream& bs) const
{
RowAggFunctionCol::serialize(bs);
fUDAFContext.serialize(bs);
}
inline void RowUDAFFunctionCol::deserialize(messageqcpp::ByteStream& bs)
{
// This deserialize is called when the function gets to PrimProc.
// reset is called because we're starting a new sub-evaluate cycle.
RowAggFunctionCol::deserialize(bs);
fUDAFContext.unserialize(bs);
fUDAFContext.setInterrupted(&bInterrupted);
mcsv1sdk::mcsv1_UDAF::ReturnCode rc;
rc = fUDAFContext.getFunction()->reset(&fUDAFContext);
if (rc == mcsv1sdk::mcsv1_UDAF::ERROR)
{
bInterrupted = true;
throw logging::QueryDataExcept(fUDAFContext.getErrorMessage(), logging::aggregateFuncErr);
}
}
struct ConstantAggData
{
std::string fConstValue;
std::string fUDAFName; // If a UDAF is called with constant.
RowAggFunctionType fOp;
bool fIsNull;
@@ -205,6 +275,10 @@ struct ConstantAggData
ConstantAggData(const std::string& v, RowAggFunctionType f, bool n) :
fConstValue(v), fOp(f), fIsNull(n)
{}
ConstantAggData(const std::string& v, const std::string u, RowAggFunctionType f, bool n) :
fConstValue(v), fUDAFName(u), fOp(f), fIsNull(n)
{}
};
typedef boost::shared_ptr<RowAggGroupByCol> SP_ROWAGG_GRPBY_t;
@@ -377,7 +451,7 @@ class RowAggregation : public messageqcpp::Serializeable
/** @brief reset RowAggregation outputRowGroup and hashMap
*/
virtual void reset();
virtual void aggReset();
/** @brief Define content of data to be aggregated and its aggregated output.
*
@@ -470,12 +544,15 @@ class RowAggregation : public messageqcpp::Serializeable
virtual void doAvg(const Row&, int64_t, int64_t, int64_t);
virtual void doStatistics(const Row&, int64_t, int64_t, int64_t);
virtual void doBitOp(const Row&, int64_t, int64_t, int);
virtual void doUDAF(const Row&, int64_t, int64_t, int64_t, RowUDAFFunctionCol* rowUDAF);
virtual bool countSpecial(const RowGroup* pRG)
{ fRow.setIntField<8>(fRow.getIntField<8>(0) + pRG->getRowCount(), 0); return true; }
virtual bool newRowGroup();
virtual void clearAggMap() { if (fAggMapPtr) fAggMapPtr->clear(); }
void resetUDAF(uint64_t funcColID);
inline bool isNull(const RowGroup* pRowGroup, const Row& row, int64_t col);
inline void makeAggFieldsNull(Row& row);
inline void copyNullRow(Row& row) { copyRow(fNullRow, &row); }
@@ -537,7 +614,6 @@ class RowAggregation : public messageqcpp::Serializeable
friend class AggComparator;
};
//------------------------------------------------------------------------------
/** @brief derived Class that aggregates multi-rowgroups on UM
* One-phase case: aggregate from projected RG to final aggregated RG.
@@ -602,7 +678,7 @@ class RowAggregationUM : public RowAggregation
void aggregateRow(Row &);
//void initialize();
virtual void reset();
virtual void aggReset();
void setInputOutput(const RowGroup& pRowGroupIn, RowGroup* pRowGroupOut);
@@ -628,6 +704,12 @@ class RowAggregationUM : public RowAggregation
// calculate the statistics function all rows received. UM only function.
void calculateStatisticsFunctions();
// Sets the value from valOut into column colOut, performing any conversions.
void SetUDAFValue(static_any::any& valOut, int64_t colOut);
// calculate the UDAF function all rows received. UM only function.
void calculateUDAFColumns();
// fix duplicates. UM only function.
void fixDuplicates(RowAggFunctionType funct);
@@ -646,6 +728,7 @@ class RowAggregationUM : public RowAggregation
bool fHasAvg;
bool fKeyOnHeap;
bool fHasStatsFunc;
bool fHasUDAF;
boost::shared_ptr<RowAggregation> fDistinctAggregator;
@@ -715,6 +798,7 @@ class RowAggregationUMP2 : public RowAggregationUM
void doStatistics(const Row&, int64_t, int64_t, int64_t);
void doGroupConcat(const Row&, int64_t, int64_t);
void doBitOp(const Row&, int64_t, int64_t, int);
void doUDAF(const Row&, int64_t, int64_t, int64_t, RowUDAFFunctionCol* rowUDAF);
bool countSpecial(const RowGroup* pRG) { return false; }
};

175
utils/rowgroup/rowgroup.cpp Normal file → Executable file
View File

@@ -38,7 +38,6 @@
using namespace std;
#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>
using namespace boost;
#include "bytestream.h"
@@ -113,7 +112,6 @@ uint32_t StringStore::storeString(const uint8_t *data, uint32_t len)
void StringStore::serialize(ByteStream &bs) const
{
uint32_t i;
std::string empty_str;
bs << (uint32_t) mem.size();
bs << (uint8_t) empty;
@@ -126,30 +124,25 @@ void StringStore::serialize(ByteStream &bs) const
}
}
uint32_t StringStore::deserialize(ByteStream &bs)
void StringStore::deserialize(ByteStream &bs)
{
uint32_t i;
uint32_t count;
uint32_t size;
std::string buf;
uint8_t tmp8;
uint32_t ret = 0;
//mem.clear();
bs >> count;
mem.reserve(count);
bs >> tmp8;
empty = (bool) tmp8;
ret += 5;
for (i = 0; i < count; i++) {
//cout << "deserializing " << size << " bytes\n";
bs >> buf;
shared_ptr<std::string> newString(new std::string(buf));
mem.push_back(newString);
//bs.advance(size);
ret += (size + 4);
}
return ret;
return;
}
void StringStore::clear()
@@ -159,6 +152,106 @@ void StringStore::clear()
empty = true;
}
UserDataStore::UserDataStore() : fUseUserDataMutex(false)
{
}
UserDataStore::~UserDataStore()
{
}
uint32_t UserDataStore::storeUserData(mcsv1sdk::mcsv1Context& context,
boost::shared_ptr<mcsv1sdk::UserData> data,
uint32_t len)
{
uint32_t ret = 0;
if (len == 0 || data == NULL)
{
return numeric_limits<uint32_t>::max();
}
boost::mutex::scoped_lock lk(fMutex, defer_lock);
if (fUseUserDataMutex)
lk.lock();
StoreData storeData;
storeData.length = len;
storeData.functionName = context.getName();
storeData.userData = data;
vStoreData.push_back(storeData);
ret = vStoreData.size();
return ret;
}
boost::shared_ptr<mcsv1sdk::UserData> UserDataStore::getUserData(uint32_t off) const
{
if (off == std::numeric_limits<uint32_t>::max())
return boost::shared_ptr<mcsv1sdk::UserData>();
if ((vStoreData.size() < off) || off == 0)
return boost::shared_ptr<mcsv1sdk::UserData>();
return vStoreData[off-1].userData;
}
void UserDataStore::serialize(ByteStream &bs) const
{
size_t i;
bs << (uint32_t) vStoreData.size();
for (i = 0; i < vStoreData.size(); ++i)
{
const StoreData& storeData = vStoreData[i];
bs << storeData.length;
bs << storeData.functionName;
storeData.userData->serialize(bs);
}
}
void UserDataStore::deserialize(ByteStream &bs)
{
size_t i;
uint32_t cnt;
bs >> cnt;
// vStoreData.clear();
vStoreData.resize(cnt);
for (i = 0; i < cnt; i++)
{
bs >> vStoreData[i].length;
bs >> vStoreData[i].functionName;
// We don't have easy access to the context here, so we do our own lookup
if (vStoreData[i].functionName.length() == 0)
{
throw std::logic_error("UserDataStore::deserialize: has empty name");
}
mcsv1sdk::UDAF_MAP::iterator funcIter = mcsv1sdk::UDAFMap::getMap().find(vStoreData[i].functionName);
if (funcIter == mcsv1sdk::UDAFMap::getMap().end())
{
std::ostringstream errmsg;
errmsg << "UserDataStore::deserialize: " << vStoreData[i].functionName << " is undefined";
throw std::logic_error(errmsg.str());
}
mcsv1sdk::mcsv1_UDAF::ReturnCode rc;
mcsv1sdk::UserData* userData = NULL;
rc = funcIter->second->createUserData(userData, vStoreData[i].length);
if (rc != mcsv1sdk::mcsv1_UDAF::SUCCESS)
{
std::ostringstream errmsg;
errmsg << "UserDataStore::deserialize: " << vStoreData[i].functionName << " createUserData failed(" << rc << ")";
throw std::logic_error(errmsg.str());
}
userData->unserialize(bs);
vStoreData[i].userData = boost::shared_ptr<mcsv1sdk::UserData>(userData);
}
return;
}
//uint32_t rgDataCount = 0;
RGData::RGData()
@@ -222,7 +315,7 @@ void RGData::reinit(const RowGroup &rg)
reinit(rg, 8192);
}
RGData::RGData(const RGData &r) : rowData(r.rowData), strings(r.strings)
RGData::RGData(const RGData &r) : rowData(r.rowData), strings(r.strings), userDataStore(r.userDataStore)
{
//cout << "rgdata++ = " << __sync_add_and_fetch(&rgDataCount, 1) << endl;
}
@@ -244,49 +337,47 @@ void RGData::serialize(ByteStream &bs, uint32_t amount) const
}
else
bs << (uint8_t) 0;
if (userDataStore)
{
bs << (uint8_t) 1;
userDataStore->serialize(bs);
}
else
bs << (uint8_t) 0;
}
uint32_t RGData::deserialize(ByteStream &bs, bool hasLenField)
void RGData::deserialize(ByteStream &bs, bool hasLenField)
{
uint32_t amount, sig;
uint8_t *buf;
uint8_t tmp8;
uint32_t ret = 0;
bs.peek(sig);
if (sig == RGDATA_SIG) {
bs >> sig;
bs >> amount;
ret += 8;
rowData.reset(new uint8_t[amount]);
buf = bs.buf();
memcpy(rowData.get(), buf, amount);
bs.advance(amount);
bs >> tmp8;
ret += amount + 1;
if (tmp8) {
strings.reset(new StringStore());
ret += strings->deserialize(bs);
strings->deserialize(bs);
}
else
strings.reset();
}
// crude backward compat. Remove after conversions are finished.
else {
if (hasLenField) {
bs >> amount;
ret += 4;
// UDAF user data
bs >> tmp8;
if (tmp8) {
userDataStore.reset(new UserDataStore());
userDataStore->deserialize(bs);
}
else
amount = bs.length();
rowData.reset(new uint8_t[amount]);
strings.reset();
buf = bs.buf();
memcpy(rowData.get(), buf, amount);
bs.advance(amount);
ret += amount;
userDataStore.reset();
}
return ret;
return;
}
void RGData::clear()
@@ -295,14 +386,25 @@ void RGData::clear()
strings.reset();
}
Row::Row() : data(NULL), strings(NULL) { }
// UserDataStore is only used for UDAF.
// Just in time construction because most of the time we don't need one.
UserDataStore* RGData::getUserDataStore()
{
if (!userDataStore)
{
userDataStore.reset(new UserDataStore);
}
return userDataStore.get();
}
Row::Row() : data(NULL), strings(NULL), userDataStore(NULL) { }
Row::Row(const Row &r) : columnCount(r.columnCount), baseRid(r.baseRid),
oldOffsets(r.oldOffsets), stOffsets(r.stOffsets),
offsets(r.offsets), colWidths(r.colWidths), types(r.types), data(r.data),
scale(r.scale), precision(r.precision), strings(r.strings),
useStringTable(r.useStringTable), hasLongStringField(r.hasLongStringField),
sTableThreshold(r.sTableThreshold), forceInline(r.forceInline)
sTableThreshold(r.sTableThreshold), forceInline(r.forceInline), userDataStore(NULL)
{ }
Row::~Row() { }
@@ -623,9 +725,10 @@ bool Row::isNullValue(uint32_t colIndex) const
break;
default: {
ostringstream os;
os << "Row::isNullValue(): got bad column type (" << types[colIndex] <<
"). Width=" << getColumnWidth(colIndex) << endl;
os << toString() << endl;
os << "Row::isNullValue(): got bad column type (";
os << types[colIndex];
os << "). Width=";
os << getColumnWidth(colIndex) << endl;
throw logic_error(os.str());
}
}
@@ -884,7 +987,9 @@ RowGroup & RowGroup::operator=(const RowGroup &r)
return *this;
}
RowGroup::~RowGroup() { }
RowGroup::~RowGroup()
{
}
void RowGroup::resetRowGroup(uint64_t rid)
{

110
utils/rowgroup/rowgroup.h Normal file → Executable file
View File

@@ -38,6 +38,7 @@
#include <stdexcept>
//#define NDEBUG
#include <cassert>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <boost/thread/mutex.hpp>
#include <cmath>
@@ -56,6 +57,7 @@
#include "bytestream.h"
#include "calpontsystemcatalog.h"
#include "exceptclasses.h"
#include "mcsv1_udaf.h"
#include "branchpred.h"
@@ -106,25 +108,74 @@ public:
void clear();
void serialize(messageqcpp::ByteStream &) const;
uint32_t deserialize(messageqcpp::ByteStream &);
void deserialize(messageqcpp::ByteStream &);
//@bug6065, make StringStore::storeString() thread safe
void useStoreStringMutex(bool b) { fUseStoreStringMutex = b; }
bool useStoreStringMutex() const { return fUseStoreStringMutex; }
private:
std::string empty_str;
StringStore(const StringStore &);
StringStore & operator=(const StringStore &);
static const uint32_t CHUNK_SIZE = 64*1024; // allocators like powers of 2
// This is an overlay b/c the underlying data needs to be any size,
// and alloc'd in one chunk. data can't be a sepatate dynamic chunk.
// and alloc'd in one chunk. data can't be a separate dynamic chunk.
std::vector<boost::shared_ptr<std::string> > mem;
bool empty;
bool fUseStoreStringMutex; //@bug6065, make StringStore::storeString() thread safe
boost::mutex fMutex;
};
// Where we store user data for UDA(n)F
class UserDataStore
{
// length represents the fixed portion length of userData.
// There may be variable length data in containers or other
// user created structures.
struct StoreData
{
int32_t length;
std::string functionName;
boost::shared_ptr<mcsv1sdk::UserData> userData;
StoreData() : length(0) { }
StoreData(const StoreData& rhs)
{
length = rhs.length;
functionName = rhs.functionName;
userData = rhs.userData;
}
};
public:
UserDataStore();
virtual ~UserDataStore();
void serialize(messageqcpp::ByteStream &) const;
void deserialize(messageqcpp::ByteStream &);
//Set to make UserDataStore thread safe
void useUserDataMutex(bool b) { fUseUserDataMutex = b; }
bool useUserDataMutex() const { return fUseUserDataMutex; }
// Returns the offset
uint32_t storeUserData(mcsv1sdk::mcsv1Context& context,
boost::shared_ptr<mcsv1sdk::UserData> data,
uint32_t length);
boost::shared_ptr<mcsv1sdk::UserData> getUserData(uint32_t offset) const;
private:
UserDataStore(const UserDataStore &);
UserDataStore & operator=(const UserDataStore &);
std::vector<StoreData> vStoreData;
bool fUseUserDataMutex;
boost::mutex fMutex;
};
#ifdef _MSC_VER
@@ -152,7 +203,7 @@ public:
// the 'hasLengthField' is there b/c PM aggregation (and possibly others) currently sends
// inline data with a length field. Once that's converted to string table format, that
// option can go away.
uint32_t deserialize(messageqcpp::ByteStream &, bool hasLengthField=false); // returns the # of bytes read
void deserialize(messageqcpp::ByteStream &, bool hasLengthField=false); // returns the # of bytes read
inline uint64_t getStringTableMemUsage();
void clear();
@@ -169,9 +220,14 @@ public:
void useStoreStringMutex(bool b) { if (strings) strings->useStoreStringMutex(b); }
bool useStoreStringMutex() const { return (strings ? (strings->useStoreStringMutex()) : false); }
UserDataStore* getUserDataStore();
// make UserDataStore::storeData() thread safe
void useUserDataMutex(bool b) { if (userDataStore) userDataStore->useUserDataMutex(b); }
bool useUserDataMutex() const { return (userDataStore ? (userDataStore->useUserDataMutex()) : false); }
boost::shared_array<uint8_t> rowData;
boost::shared_ptr<StringStore> strings;
boost::shared_ptr<UserDataStore> userDataStore;
private:
//boost::shared_array<uint8_t> rowData;
//boost::shared_ptr<StringStore> strings;
@@ -187,14 +243,17 @@ class Row
{
public:
struct Pointer {
inline Pointer() : data(NULL), strings(NULL) { }
inline Pointer() : data(NULL), strings(NULL), userDataStore(NULL) { }
// Pointer(uint8_t*) implicitly makes old code compatible with the string table impl;
// make it explicit to identify things that still might need to be changed
inline Pointer(uint8_t *d) : data(d), strings(NULL) { }
inline Pointer(uint8_t *d, StringStore *s) : data(d), strings(s) { }
inline Pointer(uint8_t *d) : data(d), strings(NULL), userDataStore(NULL) { }
inline Pointer(uint8_t *d, StringStore *s) : data(d), strings(s), userDataStore(NULL) { }
inline Pointer(uint8_t *d, StringStore *s, UserDataStore *u) :
data(d), strings(s), userDataStore(u) { }
uint8_t *data;
StringStore *strings;
UserDataStore *userDataStore;
};
Row();
@@ -290,6 +349,11 @@ class Row
inline const uint8_t* getVarBinaryField(uint32_t& len, uint32_t colIndex) const;
inline void setVarBinaryField(const uint8_t* val, uint32_t len, uint32_t colIndex);
inline boost::shared_ptr<mcsv1sdk::UserData> getUserData(uint32_t colIndex) const;
inline void setUserData(mcsv1sdk::mcsv1Context& context,
boost::shared_ptr<mcsv1sdk::UserData> userData,
uint32_t len, uint32_t colIndex);
uint64_t getNullValue(uint32_t colIndex) const;
bool isNullValue(uint32_t colIndex) const;
@@ -332,6 +396,7 @@ class Row
inline bool equals(const Row &, uint32_t lastCol) const;
inline bool equals(const Row &) const;
inline void setUserDataStore(UserDataStore* u) {userDataStore = u;}
private:
uint32_t columnCount;
uint64_t baseRid;
@@ -353,10 +418,12 @@ class Row
boost::shared_array<bool> forceInline;
inline bool inStringTable(uint32_t col) const;
UserDataStore* userDataStore; // For UDAF
friend class RowGroup;
};
inline Row::Pointer Row::getPointer() const { return Pointer(data, strings); }
inline Row::Pointer Row::getPointer() const { return Pointer(data, strings, userDataStore); }
inline uint8_t * Row::getData() const { return data; }
inline void Row::setPointer(const Pointer &p)
@@ -368,6 +435,7 @@ inline void Row::setPointer(const Pointer &p)
useStringTable = hasStrings;
offsets = (useStringTable ? stOffsets : oldOffsets);
}
userDataStore = p.userDataStore;
}
inline void Row::setData(const Pointer &p) { setPointer(p); }
@@ -613,6 +681,15 @@ inline const uint8_t* Row::getVarBinaryField(uint32_t& len, uint32_t colIndex) c
}
}
inline boost::shared_ptr<mcsv1sdk::UserData> Row::getUserData(uint32_t colIndex) const
{
if (!userDataStore)
{
return boost::shared_ptr<mcsv1sdk::UserData>();
}
return userDataStore->getUserData(*((uint32_t *) &data[offsets[colIndex]]));
}
inline double Row::getDoubleField(uint32_t colIndex) const
{
return *((double *) &data[offsets[colIndex]]);
@@ -783,6 +860,19 @@ inline void Row::setVarBinaryField(const uint8_t *val, uint32_t len, uint32_t co
}
}
inline void Row::setUserData(mcsv1sdk::mcsv1Context& context,
boost::shared_ptr<mcsv1sdk::UserData> userData,
uint32_t len, uint32_t colIndex)
{
if (!userDataStore)
{
return;
}
uint32_t offset = userDataStore->storeUserData(context, userData, len);
*((uint32_t *) &data[offsets[colIndex]]) = offset;
*((uint32_t *) &data[offsets[colIndex] + 4]) = len;
}
inline void Row::copyField(uint32_t destIndex, uint32_t srcIndex) const
{
uint32_t n = offsets[destIndex + 1] - offsets[destIndex];
@@ -1149,6 +1239,7 @@ inline void RowGroup::getRow(uint32_t rowNum, Row *r) const
r->baseRid = getBaseRid();
r->data = &(data[headerSize + (rowNum * offsets[columnCount])]);
r->strings = strings;
r->userDataStore = rgData->userDataStore.get();
}
inline void RowGroup::setData(uint8_t *d)
@@ -1523,13 +1614,14 @@ inline RGData & RGData::operator=(const RGData &r)
{
rowData = r.rowData;
strings = r.strings;
userDataStore = r.userDataStore;
return *this;
}
inline void RGData::getRow(uint32_t num, Row *row)
{
uint32_t size = row->getSize();
row->setData(Row::Pointer(&rowData[RowGroup::getHeaderSize() + (num * size)], strings.get()));
row->setData(Row::Pointer(&rowData[RowGroup::getHeaderSize() + (num * size)], strings.get(), userDataStore.get()));
}
}

434
utils/rowgroup/rowgroup.vpj Normal file → Executable file
View File

@@ -1,220 +1,220 @@
<!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
<Project
Version="10.0"
VendorName="SlickEdit"
TemplateName="GNU C/C++"
WorkingDir=".">
<Config
Name="Debug"
Type="gnuc"
DebugCallbackName="gdb"
Version="1"
OutputFile="%bdrowgroup.so"
CompilerConfigName="Latest Version">
<Menu>
<Target
Name="Compile"
MenuCaption="&amp;Compile"
Dialog="_gnuc_options_form Compile"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
OutputExts="*.o"
SaveOption="SaveCurrent"
RunFromDir="%rw">
<Exec CmdLine='g++ -c %xup %defd -g -o "%bd%n%oe" %i "%f"'/>
</Target>
<Target
Name="Link"
MenuCaption="&amp;Link"
ShowOnMenu="Never"
Dialog="_gnuc_options_form Link"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveCurrent"
RunFromDir="%rw">
<Exec CmdLine='g++ %xup -g -o "%o" %f %libs -shared -fPIC'/>
</Target>
<Target
Name="Build"
MenuCaption="&amp;Build"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine="make"/>
</Target>
<Target
Name="Rebuild"
MenuCaption="&amp;Rebuild"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="Debug"
MenuCaption="&amp;Debug"
Dialog="_gnuc_options_form Run/Debug"
BuildFirst="1"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveNone"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="Execute"
MenuCaption="E&amp;xecute"
Dialog="_gnuc_options_form Run/Debug"
BuildFirst="1"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="dash"
MenuCaption="-"
Deletable="0">
<Exec/>
</Target>
<Target
Name="GNU C Options"
MenuCaption="GNU C &amp;Options..."
ShowOnMenu="HideIfNoCmdLine"
Deletable="0"
SaveOption="SaveNone">
<Exec
CmdLine="gnucoptions"
Type="Slick-C"/>
</Target>
</Menu>
<List Name="GNUC Options">
<Item
Name="LinkerOutputType"
Value="SharedLibrary"/>
</List>
</Config>
<Config
Name="Release"
Type="gnuc"
DebugCallbackName="gdb"
Version="1"
OutputFile="%bdrowgroup.so"
CompilerConfigName="Latest Version">
<Menu>
<Target
Name="Compile"
MenuCaption="&amp;Compile"
Dialog="_gnuc_options_form Compile"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
OutputExts="*.o"
SaveOption="SaveCurrent"
RunFromDir="%rw">
<Exec CmdLine='g++ -c %xup %defd -o "%bd%n%oe" %i "%f"'/>
</Target>
<Target
Name="Link"
MenuCaption="&amp;Link"
ShowOnMenu="Never"
Dialog="_gnuc_options_form Link"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveCurrent"
RunFromDir="%rw">
<Exec CmdLine='g++ %xup -o "%o" %f %libs -shared -fPIC'/>
</Target>
<Target
Name="Build"
MenuCaption="&amp;Build"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine="make"/>
</Target>
<Target
Name="Rebuild"
MenuCaption="&amp;Rebuild"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="Debug"
MenuCaption="&amp;Debug"
Dialog="_gnuc_options_form Run/Debug"
BuildFirst="1"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveNone"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="Execute"
MenuCaption="E&amp;xecute"
Dialog="_gnuc_options_form Run/Debug"
BuildFirst="1"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="dash"
MenuCaption="-"
Deletable="0">
<Exec/>
</Target>
<Target
Name="GNU C Options"
MenuCaption="GNU C &amp;Options..."
ShowOnMenu="HideIfNoCmdLine"
Deletable="0"
SaveOption="SaveNone">
<Exec
CmdLine="gnucoptions"
Type="Slick-C"/>
</Target>
</Menu>
<List Name="GNUC Options">
<Item
Name="LinkerOutputType"
Value="SharedLibrary"/>
</List>
</Config>
<Files>
<Folder
Name="Source Files"
Filters="*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl;*.d">
<F N="rowaggregation.cpp"/>
<F N="rowgroup.cpp"/>
</Folder>
<Folder
Name="Header Files"
Filters="*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if">
<F N="rowaggregation.h"/>
<F N="rowgroup.h"/>
</Folder>
<Folder
Name="Resource Files"
Filters="*.ico;*.cur;*.dlg"/>
<Folder
Name="Bitmaps"
Filters="*.bmp"/>
<Folder
Name="Other Files"
Filters="">
<F
N="Makefile"
Type="Makefile"/>
</Folder>
</Files>
Version="10.0"
VendorName="SlickEdit"
TemplateName="GNU C/C++"
WorkingDir=".">
<Config
Name="Debug"
Type="gnuc"
DebugCallbackName="gdb"
Version="1"
OutputFile="%bdrowgroup.so"
CompilerConfigName="Latest Version">
<Menu>
<Target
Name="Compile"
MenuCaption="&amp;Compile"
Dialog="_gnuc_options_form Compile"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
OutputExts="*.o"
SaveOption="SaveCurrent"
RunFromDir="%rw">
<Exec CmdLine='g++ -c %xup %defd -g -o "%bd%n%oe" %i "%f"'/>
</Target>
<Target
Name="Link"
MenuCaption="&amp;Link"
ShowOnMenu="Never"
Dialog="_gnuc_options_form Link"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveCurrent"
RunFromDir="%rw">
<Exec CmdLine='g++ %xup -g -o "%o" %f %libs -shared -fPIC'/>
</Target>
<Target
Name="Build"
MenuCaption="&amp;Build"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine="make"/>
</Target>
<Target
Name="Rebuild"
MenuCaption="&amp;Rebuild"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="Debug"
MenuCaption="&amp;Debug"
Dialog="_gnuc_options_form Run/Debug"
BuildFirst="1"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveNone"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="Execute"
MenuCaption="E&amp;xecute"
Dialog="_gnuc_options_form Run/Debug"
BuildFirst="1"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="dash"
MenuCaption="-"
Deletable="0">
<Exec/>
</Target>
<Target
Name="GNU C Options"
MenuCaption="GNU C &amp;Options..."
ShowOnMenu="HideIfNoCmdLine"
Deletable="0"
SaveOption="SaveNone">
<Exec
CmdLine="gnucoptions"
Type="Slick-C"/>
</Target>
</Menu>
<List Name="GNUC Options">
<Item
Name="LinkerOutputType"
Value="SharedLibrary"/>
</List>
</Config>
<Config
Name="Release"
Type="gnuc"
DebugCallbackName="gdb"
Version="1"
OutputFile="%bdrowgroup.so"
CompilerConfigName="Latest Version">
<Menu>
<Target
Name="Compile"
MenuCaption="&amp;Compile"
Dialog="_gnuc_options_form Compile"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
OutputExts="*.o"
SaveOption="SaveCurrent"
RunFromDir="%rw">
<Exec CmdLine='g++ -c %xup %defd -o "%bd%n%oe" %i "%f"'/>
</Target>
<Target
Name="Link"
MenuCaption="&amp;Link"
ShowOnMenu="Never"
Dialog="_gnuc_options_form Link"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveCurrent"
RunFromDir="%rw">
<Exec CmdLine='g++ %xup -o "%o" %f %libs -shared -fPIC'/>
</Target>
<Target
Name="Build"
MenuCaption="&amp;Build"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine="make"/>
</Target>
<Target
Name="Rebuild"
MenuCaption="&amp;Rebuild"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="Debug"
MenuCaption="&amp;Debug"
Dialog="_gnuc_options_form Run/Debug"
BuildFirst="1"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveNone"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="Execute"
MenuCaption="E&amp;xecute"
Dialog="_gnuc_options_form Run/Debug"
BuildFirst="1"
CaptureOutputWith="ProcessBuffer"
Deletable="0"
SaveOption="SaveWorkspaceFiles"
RunFromDir="%rw">
<Exec CmdLine=""/>
</Target>
<Target
Name="dash"
MenuCaption="-"
Deletable="0">
<Exec/>
</Target>
<Target
Name="GNU C Options"
MenuCaption="GNU C &amp;Options..."
ShowOnMenu="HideIfNoCmdLine"
Deletable="0"
SaveOption="SaveNone">
<Exec
CmdLine="gnucoptions"
Type="Slick-C"/>
</Target>
</Menu>
<List Name="GNUC Options">
<Item
Name="LinkerOutputType"
Value="SharedLibrary"/>
</List>
</Config>
<Files>
<Folder
Name="Source Files"
Filters="*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.c++;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl;*.d">
<F N="rowaggregation.cpp"/>
<F N="rowgroup.cpp"/>
</Folder>
<Folder
Name="Header Files"
Filters="*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if">
<F N="rowaggregation.h"/>
<F N="rowgroup.h"/>
</Folder>
<Folder
Name="Resource Files"
Filters="*.ico;*.cur;*.dlg"/>
<Folder
Name="Bitmaps"
Filters="*.bmp"/>
<Folder
Name="Other Files"
Filters="">
<F
N="Makefile"
Type="Makefile"/>
</Folder>
</Files>
</Project>