mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-18 21:44:02 +03:00
1987 lines
61 KiB
C++
1987 lines
61 KiB
C++
/* Copyright (C) 2014 InfiniDB, Inc.
|
|
Copyright (C) 2019 MariaDB Corporation
|
|
|
|
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: ha_mcs_partition.cpp 9642 2013-06-24 14:57:42Z rdempsey $
|
|
*/
|
|
|
|
#include <my_config.h>
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <cassert>
|
|
#include <stdexcept>
|
|
#include <sstream>
|
|
//#include <unistd.h>
|
|
#include <iomanip>
|
|
using namespace std;
|
|
|
|
#include <boost/tokenizer.hpp>
|
|
|
|
|
|
#include "idb_mysql.h"
|
|
|
|
#include "blocksize.h"
|
|
#include "calpontsystemcatalog.h"
|
|
#include "objectidmanager.h"
|
|
using namespace execplan;
|
|
|
|
#include "mastersegmenttable.h"
|
|
#include "extentmap.h"
|
|
#include "dbrm.h"
|
|
#include "brmtypes.h"
|
|
using namespace BRM;
|
|
|
|
#include "dataconvert.h"
|
|
using namespace dataconvert;
|
|
#include "ddlpkg.h"
|
|
#include "sqlparser.h"
|
|
using namespace ddlpackage;
|
|
|
|
#include "bytestream.h"
|
|
using namespace messageqcpp;
|
|
|
|
#include "ddlpackageprocessor.h"
|
|
using namespace ddlpackageprocessor;
|
|
|
|
#include "errorids.h"
|
|
#include "idberrorinfo.h"
|
|
#include "exceptclasses.h"
|
|
using namespace logging;
|
|
|
|
#include <boost/algorithm/string/case_conv.hpp>
|
|
using namespace boost;
|
|
|
|
namespace
|
|
{
|
|
const uint8_t ROUND_POS = 0x01;
|
|
const uint8_t ROUND_NEG = 0x80;
|
|
|
|
//convenience fcn
|
|
inline uint32_t tid2sid(const uint32_t tid)
|
|
{
|
|
return CalpontSystemCatalog::idb_tid2sid(tid);
|
|
}
|
|
|
|
void CHECK( int rc)
|
|
{
|
|
if (rc != 0)
|
|
{
|
|
ostringstream oss;
|
|
oss << "Error in DBRM call " << rc << endl;
|
|
throw runtime_error(oss.str());
|
|
}
|
|
}
|
|
|
|
// partition warnings are delimited by '\n'
|
|
void push_warnings(THD* thd, string& warnings)
|
|
{
|
|
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
|
|
boost::char_separator<char> sep("\n");
|
|
tokenizer tokens(warnings, sep);
|
|
|
|
for (tokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter)
|
|
{
|
|
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 9999, (*tok_iter).c_str());
|
|
}
|
|
}
|
|
|
|
string name(CalpontSystemCatalog::ColType& ct)
|
|
{
|
|
switch (ct.colDataType)
|
|
{
|
|
case CalpontSystemCatalog::INT:
|
|
return "INT";
|
|
|
|
case CalpontSystemCatalog::TINYINT:
|
|
return "TINYINT";
|
|
|
|
case CalpontSystemCatalog::MEDINT:
|
|
return "MEDINT";
|
|
|
|
case CalpontSystemCatalog::SMALLINT:
|
|
return "SMALLINT";
|
|
|
|
case CalpontSystemCatalog::BIGINT:
|
|
return "BIGINT";
|
|
|
|
case CalpontSystemCatalog::DATE:
|
|
return "DATE";
|
|
|
|
case CalpontSystemCatalog::DATETIME:
|
|
return "DATETIME";
|
|
|
|
case CalpontSystemCatalog::TIME:
|
|
return "TIME";
|
|
|
|
case CalpontSystemCatalog::TIMESTAMP:
|
|
return "TIMESTAMP";
|
|
|
|
case CalpontSystemCatalog::DECIMAL:
|
|
return "DECIMAL";
|
|
|
|
case CalpontSystemCatalog::CHAR:
|
|
{
|
|
ostringstream oss;
|
|
oss << "CHAR(" << ct.colWidth << ")";
|
|
return oss.str();
|
|
}
|
|
|
|
case CalpontSystemCatalog::VARCHAR:
|
|
{
|
|
ostringstream oss;
|
|
oss << "VARCHAR(" << ct.colWidth << ")";
|
|
return oss.str();
|
|
}
|
|
|
|
case CalpontSystemCatalog::FLOAT:
|
|
return "FLOAT";
|
|
|
|
case CalpontSystemCatalog::DOUBLE:
|
|
return "DOUBLE";
|
|
|
|
case CalpontSystemCatalog::BIT:
|
|
return "BIT";
|
|
|
|
case CalpontSystemCatalog::VARBINARY:
|
|
return "VARBINARY";
|
|
|
|
case CalpontSystemCatalog::BLOB:
|
|
return "BLOB";
|
|
|
|
case CalpontSystemCatalog::TEXT:
|
|
return "TEXT";
|
|
|
|
case CalpontSystemCatalog::CLOB:
|
|
return "CLOB";
|
|
|
|
case CalpontSystemCatalog::UINT:
|
|
return "UINT";
|
|
|
|
case CalpontSystemCatalog::UTINYINT:
|
|
return "UTINYINT";
|
|
|
|
case CalpontSystemCatalog::UMEDINT:
|
|
return "UMEDINT";
|
|
|
|
case CalpontSystemCatalog::USMALLINT:
|
|
return "USMALLINT";
|
|
|
|
case CalpontSystemCatalog::UBIGINT:
|
|
return "UBIGINT";
|
|
|
|
case CalpontSystemCatalog::UDECIMAL:
|
|
return "UDECIMAL";
|
|
|
|
case CalpontSystemCatalog::UFLOAT:
|
|
return "UFLOAT";
|
|
|
|
case CalpontSystemCatalog::UDOUBLE:
|
|
return "UDOUBLE";
|
|
|
|
case CalpontSystemCatalog::LONGDOUBLE:
|
|
return "LONGDOUBLE";
|
|
|
|
default:
|
|
return "Unknown Type";
|
|
}
|
|
}
|
|
|
|
bool CP_type(CalpontSystemCatalog::ColType& ct)
|
|
{
|
|
if (ct.colDataType == CalpontSystemCatalog::INT ||
|
|
ct.colDataType == CalpontSystemCatalog::TINYINT ||
|
|
ct.colDataType == CalpontSystemCatalog::MEDINT ||
|
|
ct.colDataType == CalpontSystemCatalog::SMALLINT ||
|
|
ct.colDataType == CalpontSystemCatalog::BIGINT ||
|
|
ct.colDataType == CalpontSystemCatalog::DATE ||
|
|
ct.colDataType == CalpontSystemCatalog::DATETIME ||
|
|
ct.colDataType == CalpontSystemCatalog::TIME ||
|
|
ct.colDataType == CalpontSystemCatalog::TIMESTAMP ||
|
|
ct.colDataType == CalpontSystemCatalog::DECIMAL ||
|
|
ct.colDataType == CalpontSystemCatalog::UTINYINT ||
|
|
ct.colDataType == CalpontSystemCatalog::USMALLINT ||
|
|
ct.colDataType == CalpontSystemCatalog::UMEDINT ||
|
|
ct.colDataType == CalpontSystemCatalog::UINT ||
|
|
ct.colDataType == CalpontSystemCatalog::UBIGINT ||
|
|
ct.colDataType == CalpontSystemCatalog::UDECIMAL ||
|
|
(ct.colDataType == CalpontSystemCatalog::CHAR && ct.colWidth <= 8) ||
|
|
(ct.colDataType == CalpontSystemCatalog::VARCHAR && ct.colWidth <= 7))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
const uint64_t ET_DISABLED = 0x0002;
|
|
const uint64_t CPINVALID = 0x0004;
|
|
|
|
struct PartitionInfo
|
|
{
|
|
int64_t min;
|
|
int64_t max;
|
|
uint64_t status;
|
|
PartitionInfo(): min((uint64_t)0x8000000000000001ULL),
|
|
max((uint64_t) - 0x8000000000000001LL),
|
|
status(0) {};
|
|
};
|
|
|
|
typedef map<LogicalPartition, PartitionInfo> PartitionMap;
|
|
|
|
const string format(int64_t v, CalpontSystemCatalog::ColType& ct)
|
|
{
|
|
ostringstream oss;
|
|
|
|
switch (ct.colDataType)
|
|
{
|
|
case CalpontSystemCatalog::DATE:
|
|
oss << DataConvert::dateToString(v);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::DATETIME:
|
|
oss << DataConvert::datetimeToString(v);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::TIMESTAMP:
|
|
oss << DataConvert::timestampToString(v, current_thd->variables.time_zone->get_name()->ptr());
|
|
break;
|
|
|
|
case CalpontSystemCatalog::TIME:
|
|
oss << DataConvert::timeToString(v);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::CHAR:
|
|
case CalpontSystemCatalog::VARCHAR:
|
|
{
|
|
// swap again to retain the string byte order
|
|
uint64_t tmp = uint64ToStr(v);
|
|
oss << (char*)(&tmp);
|
|
break;
|
|
}
|
|
|
|
case CalpontSystemCatalog::TINYINT:
|
|
case CalpontSystemCatalog::SMALLINT:
|
|
case CalpontSystemCatalog::MEDINT:
|
|
case CalpontSystemCatalog::INT:
|
|
case CalpontSystemCatalog::BIGINT:
|
|
case CalpontSystemCatalog::DECIMAL:
|
|
case CalpontSystemCatalog::UDECIMAL:
|
|
{
|
|
if (ct.scale > 0)
|
|
{
|
|
double d = ((double)(v) / (double)pow((double)10, ct.scale));
|
|
oss << setprecision(ct.scale) << fixed << d;
|
|
}
|
|
else
|
|
{
|
|
oss << v;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CalpontSystemCatalog::UTINYINT:
|
|
case CalpontSystemCatalog::USMALLINT:
|
|
case CalpontSystemCatalog::UMEDINT:
|
|
case CalpontSystemCatalog::UINT:
|
|
case CalpontSystemCatalog::UBIGINT:
|
|
oss << static_cast<uint64_t>(v);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::VARBINARY:
|
|
oss << "N/A";
|
|
break;
|
|
|
|
default:
|
|
oss << v;
|
|
break;
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
int64_t IDB_format(char* str, CalpontSystemCatalog::ColType& ct, uint8_t& rf)
|
|
{
|
|
int64_t v = 0;
|
|
bool pushWarning = false;
|
|
rf = 0;
|
|
boost::any anyVal = DataConvert::convertColumnData(ct, str, pushWarning, current_thd->variables.time_zone->get_name()->ptr(), false, true, false);
|
|
|
|
switch (ct.colDataType)
|
|
{
|
|
case CalpontSystemCatalog::BIT:
|
|
v = boost::any_cast<bool>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::TINYINT:
|
|
v = boost::any_cast<char>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::UTINYINT:
|
|
v = boost::any_cast<uint8_t>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::SMALLINT:
|
|
v = boost::any_cast<int16_t>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::USMALLINT:
|
|
v = boost::any_cast<uint16_t>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::MEDINT:
|
|
case CalpontSystemCatalog::INT:
|
|
#ifdef _MSC_VER
|
|
v = boost::any_cast<int>(anyVal);
|
|
#else
|
|
v = boost::any_cast<int32_t>(anyVal);
|
|
#endif
|
|
break;
|
|
|
|
case CalpontSystemCatalog::UMEDINT:
|
|
case CalpontSystemCatalog::UINT:
|
|
v = boost::any_cast<uint32_t>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::BIGINT:
|
|
v = boost::any_cast<long long>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::UBIGINT:
|
|
v = boost::any_cast<uint64_t>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::CHAR:
|
|
case CalpontSystemCatalog::VARCHAR:
|
|
case CalpontSystemCatalog::VARBINARY:
|
|
case CalpontSystemCatalog::BLOB:
|
|
case CalpontSystemCatalog::TEXT:
|
|
case CalpontSystemCatalog::CLOB:
|
|
{
|
|
string i = boost::any_cast<string>(anyVal);
|
|
// bug 1932, pad nulls up to the size of v
|
|
i.resize(sizeof(v), 0);
|
|
v = uint64ToStr(*((uint64_t*) i.data()));
|
|
|
|
if (pushWarning)
|
|
rf = ROUND_POS;
|
|
}
|
|
break;
|
|
|
|
case CalpontSystemCatalog::DATE:
|
|
v = boost::any_cast<uint32_t>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::TIMESTAMP:
|
|
case CalpontSystemCatalog::DATETIME:
|
|
v = boost::any_cast<uint64_t>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::TIME:
|
|
v = boost::any_cast<int64_t>(anyVal);
|
|
break;
|
|
|
|
case CalpontSystemCatalog::DECIMAL:
|
|
case CalpontSystemCatalog::UDECIMAL:
|
|
if (ct.colWidth == execplan::CalpontSystemCatalog::ONE_BYTE)
|
|
v = boost::any_cast<char>(anyVal);
|
|
else if (ct.colWidth == execplan::CalpontSystemCatalog::TWO_BYTE)
|
|
v = boost::any_cast<int16_t>(anyVal);
|
|
else if (ct.colWidth == execplan::CalpontSystemCatalog::FOUR_BYTE)
|
|
#ifdef _MSC_VER
|
|
v = boost::any_cast<int>(anyVal);
|
|
|
|
#else
|
|
v = boost::any_cast<int32_t>(anyVal);
|
|
#endif
|
|
else
|
|
v = boost::any_cast<long long>(anyVal);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ((ct.colDataType == CalpontSystemCatalog::TINYINT ||
|
|
ct.colDataType == CalpontSystemCatalog::SMALLINT ||
|
|
ct.colDataType == CalpontSystemCatalog::MEDINT ||
|
|
ct.colDataType == CalpontSystemCatalog::INT ||
|
|
ct.colDataType == CalpontSystemCatalog::BIGINT ||
|
|
ct.colDataType == CalpontSystemCatalog::DECIMAL ||
|
|
ct.colDataType == CalpontSystemCatalog::UDECIMAL) &&
|
|
pushWarning)
|
|
{
|
|
// get rid of leading white spaces and parentheses
|
|
string data(str);
|
|
size_t fpos = data.find_first_of(" \t()");
|
|
|
|
while (string::npos != fpos)
|
|
{
|
|
data.erase(fpos, 1);
|
|
fpos = data.find_first_of(" \t()");
|
|
}
|
|
|
|
rf = (data[0] == '-') ? ROUND_NEG : ROUND_POS;
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
|
|
void parsePartitionString(UDF_ARGS* args,
|
|
int offset,
|
|
set<LogicalPartition>& partitionNums,
|
|
string& errMsg,
|
|
execplan::CalpontSystemCatalog::TableName tableName)
|
|
{
|
|
//@Bug 4695
|
|
algorithm::to_lower(tableName.schema);
|
|
|
|
if (tableName.schema == "calpontsys")
|
|
{
|
|
errMsg = IDBErrorInfo::instance()->errorMsg(SYSTABLE_PARTITION);
|
|
return;
|
|
}
|
|
|
|
partitionNums.clear();
|
|
|
|
string partStr = args->args[offset];
|
|
char* partStrNoSpace = (char*)alloca(partStr.length() + 1);
|
|
char* tmp = partStrNoSpace;
|
|
|
|
// trim off space
|
|
for (uint32_t i = 0; i < partStr.length(); i++)
|
|
{
|
|
if (partStr[i] == ' ' || partStr[i] == '\t')
|
|
continue;
|
|
|
|
*tmp = partStr[i];
|
|
++tmp;
|
|
}
|
|
|
|
*tmp = 0;
|
|
string parts(partStrNoSpace);
|
|
|
|
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
|
|
boost::char_separator<char> sep(",");
|
|
boost::char_separator<char> sep1(".");
|
|
tokenizer tokens(parts, sep);
|
|
stringstream ss (stringstream::in | stringstream::out);
|
|
|
|
for (tokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter)
|
|
{
|
|
//cout << "token " << (*tok_iter) << endl;
|
|
LogicalPartition lp;
|
|
|
|
tokenizer tokens1((*tok_iter), sep1);
|
|
uint32_t ctn = 0;
|
|
|
|
for (tokenizer::iterator tok_iter1 = tokens1.begin(); tok_iter1 != tokens1.end(); ++tok_iter1, ctn++)
|
|
{
|
|
ss << *tok_iter1;
|
|
|
|
switch (ctn)
|
|
{
|
|
case 0:
|
|
if (ss >> lp.pp && ss.eof())
|
|
break;
|
|
|
|
goto error;
|
|
|
|
case 1:
|
|
if (ss >> lp.seg && ss.eof())
|
|
break;
|
|
|
|
goto error;
|
|
|
|
case 2:
|
|
if (ss >> lp.dbroot && ss.eof())
|
|
break;
|
|
|
|
goto error;
|
|
|
|
default:
|
|
goto error;
|
|
}
|
|
|
|
ss.clear();
|
|
ss.str("");
|
|
}
|
|
|
|
partitionNums.insert(lp);
|
|
}
|
|
|
|
if (partitionNums.empty())
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
return;
|
|
|
|
error:
|
|
errMsg = "Invalid partition identifier(s)";
|
|
return;
|
|
|
|
// debug
|
|
set<LogicalPartition>::const_iterator it;
|
|
cout << "Partition: ";
|
|
|
|
for (it = partitionNums.begin(); it != partitionNums.end(); ++it)
|
|
cout << (*it) << endl;
|
|
}
|
|
|
|
int processPartition ( SqlStatement* stmt)
|
|
{
|
|
//cout << "Sending to DDLProc" << endl;
|
|
ByteStream bytestream;
|
|
bytestream << stmt->fSessionID;
|
|
stmt->serialize(bytestream);
|
|
MessageQueueClient mq("DDLProc");
|
|
ByteStream::byte b = 0;
|
|
int rc = 0;
|
|
THD* thd = current_thd;
|
|
string emsg;
|
|
|
|
try
|
|
{
|
|
mq.write(bytestream);
|
|
bytestream = mq.read();
|
|
|
|
if ( bytestream.length() == 0 )
|
|
{
|
|
rc = 1;
|
|
thd->get_stmt_da()->set_overwrite_status(true);
|
|
thd->raise_error_printf(ER_INTERNAL_ERROR, "Lost connection to DDLProc");
|
|
}
|
|
else
|
|
{
|
|
bytestream >> b;
|
|
bytestream >> emsg;
|
|
rc = b;
|
|
}
|
|
}
|
|
catch (runtime_error&)
|
|
{
|
|
rc = 1;
|
|
thd->get_stmt_da()->set_overwrite_status(true);
|
|
thd->raise_error_printf(ER_INTERNAL_ERROR, "Lost connection to DDLProc");
|
|
}
|
|
catch (...)
|
|
{
|
|
rc = 1;
|
|
thd->get_stmt_da()->set_overwrite_status(true);
|
|
thd->raise_error_printf(ER_INTERNAL_ERROR, "Unknown error caught");
|
|
}
|
|
|
|
if (b == ddlpackageprocessor::DDLPackageProcessor::WARN_NO_PARTITION)
|
|
{
|
|
rc = b;
|
|
push_warnings(thd, emsg);
|
|
}
|
|
else if (b == ddlpackageprocessor::DDLPackageProcessor::PARTITION_WARNING)
|
|
{
|
|
rc = 0;
|
|
push_warnings(thd, emsg);
|
|
}
|
|
else if (b == ddlpackageprocessor::DDLPackageProcessor::WARNING)
|
|
{
|
|
rc = 0;
|
|
string errmsg ("Error occured during partitioning operation. Restart DMLProc or use command tool ddlcleanup to clean up. " );
|
|
push_warnings(thd, errmsg);
|
|
}
|
|
else if (b != 0 && b != ddlpackageprocessor::DDLPackageProcessor::WARN_NO_PARTITION)
|
|
{
|
|
thd->get_stmt_da()->set_overwrite_status(true);
|
|
thd->raise_error_printf(ER_INTERNAL_ERROR, emsg.c_str());
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void partitionByValue_common(UDF_ARGS* args, // input
|
|
string& errMsg, // output
|
|
CalpontSystemCatalog::TableName& tableName, // output
|
|
set<LogicalPartition>& partSet, // output
|
|
string functionName) // input
|
|
{
|
|
// identify partitions by the range
|
|
DBRM em;
|
|
vector<struct EMEntry> entries;
|
|
vector<struct EMEntry>::iterator iter;
|
|
PartitionMap partMap;
|
|
PartitionMap::iterator mapit;
|
|
int32_t seqNum;
|
|
string schema, table, column;
|
|
CalpontSystemCatalog::ColType ct;
|
|
int64_t startVal, endVal;
|
|
uint8_t rfMin = 0, rfMax = 0;
|
|
|
|
if (args->arg_count == 5)
|
|
{
|
|
schema = (char*)(args->args[0]);
|
|
table = (char*)(args->args[1]);
|
|
column = (char*)(args->args[2]);
|
|
}
|
|
else
|
|
{
|
|
if (current_thd->db.length)
|
|
{
|
|
schema = current_thd->db.str;
|
|
}
|
|
else
|
|
{
|
|
errMsg = IDBErrorInfo::instance()->errorMsg(ERR_PARTITION_NO_SCHEMA);
|
|
return;
|
|
}
|
|
|
|
table = (char*)(args->args[0]);
|
|
column = (char*)(args->args[1]);
|
|
}
|
|
|
|
tableName.schema = schema;
|
|
tableName.table = table;
|
|
|
|
//@Bug 4695
|
|
algorithm::to_lower(tableName.schema);
|
|
|
|
if (tableName.schema == "calpontsys")
|
|
{
|
|
errMsg = IDBErrorInfo::instance()->errorMsg(SYSTABLE_PARTITION);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
boost::shared_ptr<CalpontSystemCatalog> csc = CalpontSystemCatalog::makeCalpontSystemCatalog(tid2sid(current_thd->thread_id));
|
|
csc->identity(execplan::CalpontSystemCatalog::FE);
|
|
CalpontSystemCatalog::TableColName tcn = make_tcn(schema, table, column);
|
|
csc->identity(CalpontSystemCatalog::FE);
|
|
OID_t oid = csc->lookupOID(tcn);
|
|
ct = csc->colType(oid);
|
|
|
|
if (oid == -1)
|
|
{
|
|
Message::Args args;
|
|
args.add("'" + schema + string(".") + table + string(".") + column + "'");
|
|
errMsg = IDBErrorInfo::instance()->errorMsg(ERR_TABLE_NOT_IN_CATALOG, args);
|
|
return;
|
|
}
|
|
|
|
// check casual partition data type
|
|
if (!CP_type(ct))
|
|
{
|
|
Message::Args args;
|
|
args.add(name(ct));
|
|
args.add(functionName);
|
|
errMsg = IDBErrorInfo::instance()->errorMsg(ERR_PARTITION_BY_RANGE, args);
|
|
return;
|
|
}
|
|
|
|
if (args->arg_count == 4)
|
|
{
|
|
if (!args->args[2])
|
|
{
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
startVal = 0;
|
|
}
|
|
else
|
|
{
|
|
startVal = numeric_limits<int64_t>::min();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
startVal = IDB_format((char*) args->args[2], ct, rfMin);
|
|
}
|
|
|
|
if (!args->args[3])
|
|
{
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
endVal = static_cast<int64_t>(numeric_limits<uint64_t>::max());
|
|
}
|
|
else
|
|
{
|
|
endVal = numeric_limits<int64_t>::max();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
endVal = IDB_format((char*) args->args[3], ct, rfMax);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!args->args[3])
|
|
{
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
startVal = 0;
|
|
}
|
|
else
|
|
{
|
|
startVal = numeric_limits<int64_t>::min();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
startVal = IDB_format((char*) args->args[3], ct, rfMin);
|
|
}
|
|
|
|
if (!args->args[4])
|
|
{
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
endVal = static_cast<int64_t>(numeric_limits<uint64_t>::max());
|
|
}
|
|
else
|
|
{
|
|
endVal = numeric_limits<int64_t>::max();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
endVal = IDB_format((char*) args->args[4], ct, rfMax);
|
|
}
|
|
}
|
|
|
|
CHECK(em.getExtents(oid, entries, false, false, true));
|
|
|
|
if (entries.size() > 0)
|
|
{
|
|
LogicalPartition logicalPartNum;
|
|
|
|
for (iter = entries.begin(); iter != entries.end(); ++iter)
|
|
{
|
|
PartitionInfo partInfo;
|
|
logicalPartNum.dbroot = (*iter).dbRoot;
|
|
logicalPartNum.pp = (*iter).partitionNum;
|
|
logicalPartNum.seg = (*iter).segmentNum;
|
|
|
|
if (iter->status == EXTENTOUTOFSERVICE)
|
|
partInfo.status |= ET_DISABLED;
|
|
|
|
mapit = partMap.find(logicalPartNum);
|
|
int state = em.getExtentMaxMin(iter->range.start, partInfo.max, partInfo.min, seqNum);
|
|
|
|
// char column order swap
|
|
if ((ct.colDataType == CalpontSystemCatalog::CHAR && ct.colWidth <= 8) ||
|
|
(ct.colDataType == CalpontSystemCatalog::VARCHAR && ct.colWidth <= 7))
|
|
{
|
|
partInfo.max = uint64ToStr(partInfo.max);
|
|
partInfo.min = uint64ToStr(partInfo.min);
|
|
}
|
|
|
|
if (mapit == partMap.end())
|
|
{
|
|
if (state != CP_VALID)
|
|
partInfo.status |= CPINVALID;
|
|
|
|
partMap[logicalPartNum] = partInfo;
|
|
}
|
|
else
|
|
{
|
|
if (mapit->second.status & CPINVALID)
|
|
continue;
|
|
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
mapit->second.min =
|
|
(static_cast<uint64_t>(partInfo.min) < static_cast<uint64_t>(mapit->second.min) ? partInfo.min : mapit->second.min);
|
|
mapit->second.max =
|
|
(static_cast<uint64_t>(partInfo.max) > static_cast<uint64_t>(mapit->second.max) ? partInfo.max : mapit->second.max);
|
|
}
|
|
else
|
|
{
|
|
mapit->second.min = (partInfo.min < mapit->second.min ? partInfo.min : mapit->second.min);
|
|
mapit->second.max = (partInfo.max > mapit->second.max ? partInfo.max : mapit->second.max);
|
|
}
|
|
}
|
|
}
|
|
|
|
// check col value range
|
|
for (mapit = partMap.begin(); mapit != partMap.end(); ++mapit)
|
|
{
|
|
// @bug 4595. check empty/null case
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
if (!(mapit->second.status & CPINVALID) &&
|
|
static_cast<uint64_t>(mapit->second.min) >= static_cast<uint64_t>(startVal) &&
|
|
static_cast<uint64_t>(mapit->second.max) <= static_cast<uint64_t>(endVal) &&
|
|
!(static_cast<uint64_t>(mapit->second.min) == numeric_limits<uint64_t>::max() &&
|
|
static_cast<uint64_t>(mapit->second.max == 0)))
|
|
{
|
|
if (rfMin == ROUND_POS && mapit->second.min == startVal)
|
|
continue;
|
|
|
|
if (rfMax == ROUND_NEG && mapit->second.max == endVal)
|
|
continue;
|
|
|
|
partSet.insert(mapit->first);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(mapit->second.status & CPINVALID) && mapit->second.min >= startVal && mapit->second.max <= endVal &&
|
|
!(mapit->second.min == numeric_limits<int64_t>::max() && mapit->second.max == numeric_limits<int64_t>::min()))
|
|
{
|
|
if (rfMin == ROUND_POS && mapit->second.min == startVal)
|
|
continue;
|
|
|
|
if (rfMax == ROUND_NEG && mapit->second.max == endVal)
|
|
continue;
|
|
|
|
partSet.insert(mapit->first);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (QueryDataExcept& ex)
|
|
{
|
|
Message::Args args;
|
|
args.add(ex.what());
|
|
errMsg = IDBErrorInfo::instance()->errorMsg(ERR_INVALID_FUNC_ARGUMENT, args);
|
|
return;
|
|
}
|
|
catch (IDBExcept& ex)
|
|
{
|
|
errMsg = ex.what();
|
|
return;
|
|
}
|
|
catch (...)
|
|
{
|
|
errMsg = string("Error occured when calling ") + functionName;
|
|
return;
|
|
}
|
|
|
|
if (partSet.empty())
|
|
{
|
|
errMsg = IDBErrorInfo::instance()->errorMsg(WARN_NO_PARTITION_FOUND);
|
|
return;
|
|
}
|
|
}
|
|
|
|
std::string ha_mcs_impl_markpartitions_(
|
|
execplan::CalpontSystemCatalog::TableName tableName, set<LogicalPartition>& partitionNums)
|
|
{
|
|
ddlpackage::QualifiedName* qualifiedName = new QualifiedName();
|
|
qualifiedName->fSchema = tableName.schema;
|
|
qualifiedName->fName = tableName.table;
|
|
MarkPartitionStatement* stmt = new MarkPartitionStatement(qualifiedName);
|
|
stmt->fSessionID = tid2sid(current_thd->thread_id);
|
|
stmt->fSql = "caldisablepartitions";
|
|
stmt->fOwner = tableName.schema;
|
|
stmt->fPartitions = partitionNums;
|
|
string msg = "Partitions are disabled successfully" ;
|
|
|
|
int rc = processPartition( stmt); // warnings will be pushed in the function
|
|
|
|
if (rc == ddlpackageprocessor::DDLPackageProcessor::WARN_NO_PARTITION)
|
|
msg = "No partitions are disabled";
|
|
|
|
delete stmt;
|
|
return msg;
|
|
}
|
|
|
|
std::string ha_mcs_impl_restorepartitions_(
|
|
execplan::CalpontSystemCatalog::TableName tableName, set<LogicalPartition>& partitionNums)
|
|
{
|
|
ddlpackage::QualifiedName* qualifiedName = new QualifiedName();
|
|
qualifiedName->fSchema = tableName.schema;
|
|
qualifiedName->fName = tableName.table;
|
|
RestorePartitionStatement* stmt = new RestorePartitionStatement(qualifiedName);
|
|
stmt->fSessionID = tid2sid(current_thd->thread_id);
|
|
stmt->fSql = "calenablepartitions";
|
|
stmt->fOwner = tableName.schema;
|
|
stmt->fPartitions = partitionNums;
|
|
string msg;
|
|
int rc = processPartition( stmt);
|
|
|
|
if ( rc != 0 )
|
|
return msg;
|
|
|
|
msg = "Partitions are enabled successfully." ;
|
|
|
|
delete stmt;
|
|
return msg;
|
|
}
|
|
|
|
std::string ha_mcs_impl_droppartitions_(
|
|
execplan::CalpontSystemCatalog::TableName tableName, set<LogicalPartition>& partitionNums)
|
|
{
|
|
ddlpackage::QualifiedName* qualifiedName = new QualifiedName();
|
|
qualifiedName->fSchema = tableName.schema;
|
|
qualifiedName->fName = tableName.table;
|
|
DropPartitionStatement* stmt = new DropPartitionStatement(qualifiedName);
|
|
stmt->fSessionID = tid2sid(current_thd->thread_id);
|
|
stmt->fSql = "caldroppartitions";
|
|
stmt->fOwner = tableName.schema;
|
|
stmt->fPartitions = partitionNums;
|
|
string msg = "Partitions are dropped successfully" ;
|
|
|
|
int rc = processPartition( stmt);
|
|
|
|
if (rc == ddlpackageprocessor::DDLPackageProcessor::WARN_NO_PARTITION)
|
|
msg = "No partitions are dropped";
|
|
|
|
delete stmt;
|
|
return msg;
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
|
|
/**
|
|
* CalShowPartitions
|
|
*/
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
my_bool calshowpartitions_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
|
|
{
|
|
if (args->arg_count < 2 ||
|
|
args->arg_count > 3 ||
|
|
args->arg_type[0] != STRING_RESULT ||
|
|
args->arg_type[1] != STRING_RESULT ||
|
|
(args->arg_count == 3 && args->arg_type[2] != STRING_RESULT))
|
|
{
|
|
strcpy(message, "usage: CALSHOWPARTITIONS ([schema], table, column)");
|
|
return 1;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < args->arg_count; i++)
|
|
{
|
|
if (!args->args[i])
|
|
{
|
|
strcpy(message, "usage: CALSHOWPARTITIONS ([schema], table, column)");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
void calshowpartitions_deinit(UDF_INIT* initid)
|
|
{
|
|
delete initid->ptr;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
const char* calshowpartitions(UDF_INIT* initid, UDF_ARGS* args,
|
|
char* result, unsigned long* length,
|
|
char* is_null, char* error)
|
|
{
|
|
DBRM em;
|
|
vector<struct EMEntry> entries;
|
|
vector<struct EMEntry>::iterator iter;
|
|
vector<struct EMEntry>::iterator end;
|
|
PartitionMap partMap;
|
|
int32_t seqNum;
|
|
string schema, table, column;
|
|
CalpontSystemCatalog::ColType ct;
|
|
string errMsg;
|
|
|
|
try
|
|
{
|
|
PartitionMap::iterator mapit;
|
|
|
|
if (args->arg_count == 3)
|
|
{
|
|
schema = (char*)(args->args[0]);
|
|
table = (char*)(args->args[1]);
|
|
column = (char*)(args->args[2]);
|
|
}
|
|
else
|
|
{
|
|
if (current_thd->db.length)
|
|
{
|
|
schema = current_thd->db.str;
|
|
}
|
|
else
|
|
{
|
|
throw IDBExcept(ERR_PARTITION_NO_SCHEMA);
|
|
}
|
|
|
|
table = (char*)(args->args[0]);
|
|
column = (char*)(args->args[1]);
|
|
}
|
|
|
|
boost::shared_ptr<CalpontSystemCatalog> csc = CalpontSystemCatalog::makeCalpontSystemCatalog(tid2sid(current_thd->thread_id));
|
|
csc->identity(CalpontSystemCatalog::FE);
|
|
CalpontSystemCatalog::TableColName tcn = make_tcn(schema, table, column);
|
|
OID_t oid = csc->lookupOID(tcn);
|
|
ct = csc->colType(oid);
|
|
|
|
if (oid == -1)
|
|
{
|
|
Message::Args args;
|
|
args.add("'" + schema + string(".") + table + string(".") + column + "'");
|
|
throw IDBExcept(ERR_TABLE_NOT_IN_CATALOG, args);
|
|
}
|
|
|
|
CHECK(em.getExtents(oid, entries, false, false, true));
|
|
|
|
if (entries.size() > 0)
|
|
{
|
|
iter = entries.begin();
|
|
end = entries.end();
|
|
LogicalPartition logicalPartNum;
|
|
|
|
for (; iter != end; ++iter)
|
|
{
|
|
PartitionInfo partInfo;
|
|
logicalPartNum.dbroot = (*iter).dbRoot;
|
|
logicalPartNum.pp = (*iter).partitionNum;
|
|
logicalPartNum.seg = (*iter).segmentNum;
|
|
|
|
if (iter->status == EXTENTOUTOFSERVICE)
|
|
partInfo.status |= ET_DISABLED;
|
|
|
|
mapit = partMap.find(logicalPartNum);
|
|
int state = em.getExtentMaxMin(iter->range.start, partInfo.max, partInfo.min, seqNum);
|
|
|
|
// char column order swap for compare
|
|
if ((ct.colDataType == CalpontSystemCatalog::CHAR && ct.colWidth <= 8) ||
|
|
(ct.colDataType == CalpontSystemCatalog::VARCHAR && ct.colWidth <= 7))
|
|
{
|
|
partInfo.max = uint64ToStr(partInfo.max);
|
|
partInfo.min = uint64ToStr(partInfo.min);
|
|
}
|
|
|
|
if (mapit == partMap.end())
|
|
{
|
|
if (state != CP_VALID)
|
|
partInfo.status |= CPINVALID;
|
|
|
|
partMap[logicalPartNum] = partInfo;
|
|
}
|
|
else
|
|
{
|
|
if (mapit->second.status & CPINVALID)
|
|
continue;
|
|
|
|
mapit->second.min = (partInfo.min < mapit->second.min ? partInfo.min : mapit->second.min);
|
|
mapit->second.max = (partInfo.max > mapit->second.max ? partInfo.max : mapit->second.max);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (IDBExcept& ex)
|
|
{
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, ex.what());
|
|
return result;
|
|
}
|
|
catch (...)
|
|
{
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, "Error occured when calling CALSHOWPARTITIONS");
|
|
return result;
|
|
}
|
|
|
|
ostringstream output;
|
|
output.setf(ios::left, ios::adjustfield);
|
|
output << setw(10) << "Part#"
|
|
<< setw(30) << "Min"
|
|
<< setw(30) << "Max" << "Status";
|
|
|
|
int64_t maxLimit = numeric_limits<int64_t>::max();
|
|
int64_t minLimit = numeric_limits<int64_t>::min();
|
|
|
|
// char column order swap for compare in subsequent loop
|
|
if ((ct.colDataType == CalpontSystemCatalog::CHAR && ct.colWidth <= 8) ||
|
|
(ct.colDataType == CalpontSystemCatalog::VARCHAR && ct.colWidth <= 7))
|
|
{
|
|
maxLimit = uint64ToStr(maxLimit);
|
|
minLimit = uint64ToStr(minLimit);
|
|
}
|
|
|
|
PartitionMap::const_iterator partIt;
|
|
|
|
for (partIt = partMap.begin(); partIt != partMap.end(); ++partIt)
|
|
{
|
|
ostringstream oss;
|
|
oss << partIt->first;
|
|
output << "\n " << setw(10) << oss.str();
|
|
|
|
if (partIt->second.status & CPINVALID)
|
|
{
|
|
output << setw(30) << "N/A" << setw(30) << "N/A";
|
|
}
|
|
else
|
|
{
|
|
if ((isUnsigned(ct.colDataType)))
|
|
{
|
|
if (static_cast<uint64_t>(partIt->second.min) == numeric_limits<uint64_t>::max()
|
|
&& static_cast<uint64_t>(partIt->second.max) == numeric_limits<uint64_t>::min())
|
|
output << setw(30) << "Empty/Null" << setw(30) << "Empty/Null";
|
|
else
|
|
output << setw(30) << format(partIt->second.min, ct) << setw(30) << format(partIt->second.max, ct);
|
|
}
|
|
else
|
|
{
|
|
if (partIt->second.min == maxLimit && partIt->second.max == minLimit)
|
|
output << setw(30) << "Empty/Null" << setw(30) << "Empty/Null";
|
|
else
|
|
output << setw(30) << format(partIt->second.min, ct) << setw(30) << format(partIt->second.max, ct);
|
|
}
|
|
}
|
|
|
|
if (partIt->second.status & ET_DISABLED)
|
|
output << "Disabled";
|
|
else
|
|
output << "Enabled";
|
|
}
|
|
|
|
// use our own buffer to make sure it fits.
|
|
initid->ptr = new char[output.str().length() + 1];
|
|
memcpy(initid->ptr, output.str().c_str(), output.str().length());
|
|
*length = output.str().length();
|
|
return initid->ptr;
|
|
}
|
|
|
|
|
|
/**
|
|
* CalDisablePartitions
|
|
*/
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
my_bool caldisablepartitions_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
|
|
{
|
|
bool err = false;
|
|
|
|
if (args->arg_count < 2 || args->arg_count > 3)
|
|
err = true;
|
|
else if (args->arg_count == 3 && ((args->arg_type[0] != STRING_RESULT ||
|
|
args->arg_type[1] != STRING_RESULT ||
|
|
args->arg_type[2] != STRING_RESULT)))
|
|
err = true;
|
|
else if (args->arg_count == 2 && ((args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT)))
|
|
err = true;
|
|
|
|
for (uint32_t i = 0; i < args->arg_count; i++)
|
|
{
|
|
if (!args->args[i])
|
|
{
|
|
err = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
strcpy(message, "\nusage: CALDISABLEPARTITIONS (['schemaName'], 'tableName', 'partitionList')");
|
|
return 1;
|
|
}
|
|
|
|
initid->maybe_null = 1;
|
|
initid->max_length = 255;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
const char* caldisablepartitions(UDF_INIT* initid, UDF_ARGS* args,
|
|
char* result, unsigned long* length,
|
|
char* is_null, char* error)
|
|
{
|
|
CalpontSystemCatalog::TableName tableName;
|
|
set <LogicalPartition> partitionNums;
|
|
string errMsg;
|
|
|
|
if ( args->arg_count == 3 )
|
|
{
|
|
tableName.schema = args->args[0];
|
|
tableName.table = args->args[1];
|
|
parsePartitionString(args, 2, partitionNums, errMsg, tableName);
|
|
}
|
|
else
|
|
{
|
|
tableName.table = args->args[0];
|
|
|
|
if (!current_thd->db.length)
|
|
{
|
|
errMsg = "No schema name indicated.";
|
|
memcpy(result, errMsg.c_str(), errMsg.length());
|
|
*length = errMsg.length();
|
|
return result;
|
|
}
|
|
|
|
tableName.schema = current_thd->db.str;
|
|
parsePartitionString(args, 1, partitionNums, errMsg, tableName);
|
|
}
|
|
|
|
if (errMsg.empty())
|
|
errMsg = ha_mcs_impl_markpartitions_(tableName, partitionNums );
|
|
|
|
memcpy(result, errMsg.c_str(), errMsg.length());
|
|
*length = errMsg.length();
|
|
return result;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
void caldisablepartitions_deinit(UDF_INIT* initid)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* CalEnablePartitions
|
|
*/
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
my_bool calenablepartitions_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
|
|
{
|
|
bool err = false;
|
|
|
|
if (args->arg_count < 2 || args->arg_count > 3)
|
|
err = true;
|
|
else if (args->arg_count == 3 && ((args->arg_type[0] != STRING_RESULT ||
|
|
args->arg_type[1] != STRING_RESULT ||
|
|
args->arg_type[2] != STRING_RESULT)))
|
|
err = true;
|
|
else if (args->arg_count == 2 && ((args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT)))
|
|
err = true;
|
|
|
|
for (uint32_t i = 0; i < args->arg_count; i++)
|
|
{
|
|
if (!args->args[i])
|
|
{
|
|
err = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
strcpy(message, "\nusage: CALENABLEPARTITIONS (['schemaName'], 'tableName', 'partitionList')");
|
|
return 1;
|
|
}
|
|
|
|
initid->maybe_null = 1;
|
|
initid->max_length = 255;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
const char* calenablepartitions(UDF_INIT* initid, UDF_ARGS* args,
|
|
char* result, unsigned long* length,
|
|
char* is_null, char* error)
|
|
{
|
|
CalpontSystemCatalog::TableName tableName;
|
|
string errMsg;
|
|
set<LogicalPartition> partitionNums;
|
|
|
|
if ( args->arg_count == 3 )
|
|
{
|
|
tableName.schema = args->args[0];
|
|
tableName.table = args->args[1];
|
|
parsePartitionString(args, 2, partitionNums, errMsg, tableName);
|
|
}
|
|
else
|
|
{
|
|
tableName.table = args->args[0];
|
|
|
|
if (!current_thd->db.length)
|
|
{
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, IDBErrorInfo::instance()->errorMsg(ERR_PARTITION_NO_SCHEMA).c_str());
|
|
return result;
|
|
}
|
|
|
|
tableName.schema = current_thd->db.str;
|
|
parsePartitionString(args, 1, partitionNums, errMsg, tableName);
|
|
}
|
|
|
|
if (errMsg.empty())
|
|
errMsg = ha_mcs_impl_restorepartitions_(tableName, partitionNums );
|
|
|
|
memcpy(result, errMsg.c_str(), errMsg.length());
|
|
*length = errMsg.length();
|
|
return result;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
void calenablepartitions_deinit(UDF_INIT* initid)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* CalDropPartitions
|
|
*/
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
my_bool caldroppartitions_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
|
|
{
|
|
bool err = false;
|
|
|
|
if (args->arg_count < 2 || args->arg_count > 3)
|
|
err = true;
|
|
else if (args->arg_count == 3 && ((args->arg_type[0] != STRING_RESULT ||
|
|
args->arg_type[1] != STRING_RESULT ||
|
|
args->arg_type[2] != STRING_RESULT)))
|
|
err = true;
|
|
else if (args->arg_count == 2 && ((args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT)))
|
|
err = true;
|
|
|
|
for (uint32_t i = 0; i < args->arg_count; i++)
|
|
{
|
|
if (!args->args[i])
|
|
{
|
|
err = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
strcpy(message, "\nusage: CALDROPPARTITIONS (['schemaName'], 'tableName', 'partitionList')");
|
|
return 1;
|
|
}
|
|
|
|
initid->maybe_null = 1;
|
|
initid->max_length = 255;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
const char* caldroppartitions(UDF_INIT* initid, UDF_ARGS* args,
|
|
char* result, unsigned long* length,
|
|
char* is_null, char* error)
|
|
{
|
|
CalpontSystemCatalog::TableName tableName;
|
|
string errMsg;
|
|
set<LogicalPartition> partSet;
|
|
|
|
if ( args->arg_count == 3 )
|
|
{
|
|
tableName.schema = args->args[0];
|
|
tableName.table = args->args[1];
|
|
parsePartitionString(args, 2, partSet, errMsg, tableName);
|
|
}
|
|
else
|
|
{
|
|
tableName.table = args->args[0];
|
|
|
|
if (!current_thd->db.length)
|
|
{
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, IDBErrorInfo::instance()->errorMsg(ERR_PARTITION_NO_SCHEMA).c_str());
|
|
return result;
|
|
}
|
|
|
|
tableName.schema = current_thd->db.str;
|
|
parsePartitionString(args, 1, partSet, errMsg, tableName);
|
|
}
|
|
|
|
if (errMsg.empty())
|
|
errMsg = ha_mcs_impl_droppartitions_(tableName, partSet);
|
|
|
|
memcpy(result, errMsg.c_str(), errMsg.length());
|
|
*length = errMsg.length();
|
|
return result;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
void caldroppartitions_deinit(UDF_INIT* initid)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* CalDropPartitionsByValue
|
|
*/
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
void caldroppartitionsbyvalue_deinit(UDF_INIT* initid)
|
|
{
|
|
}
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
my_bool caldroppartitionsbyvalue_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
|
|
{
|
|
bool err = false;
|
|
|
|
if (args->arg_count < 4 || args->arg_count > 5)
|
|
{
|
|
err = true;
|
|
}
|
|
else if (args->arg_count == 4)
|
|
{
|
|
if (args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT || args->arg_type[2] != STRING_RESULT)
|
|
err = true;
|
|
}
|
|
else if (args->arg_count == 5)
|
|
{
|
|
if (args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT ||
|
|
args->arg_type[2] != STRING_RESULT || args->arg_type[3] != STRING_RESULT || args->arg_type[4] != STRING_RESULT)
|
|
err = true;
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
string msg = "\nusage: CALDROPPARTITIONSBYVALUE (['schema'], 'table', 'column', 'min', 'max')";
|
|
//message = new char[msg.length()+1];
|
|
strcpy(message, msg.c_str());
|
|
message[msg.length()] = 0;
|
|
//*length = msg.length();
|
|
return 1;
|
|
}
|
|
|
|
initid->maybe_null = 1;
|
|
initid->max_length = 255;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
const char* caldroppartitionsbyvalue(UDF_INIT* initid, UDF_ARGS* args,
|
|
char* result, unsigned long* length,
|
|
char* is_null, char* error)
|
|
{
|
|
string msg;
|
|
CalpontSystemCatalog::TableName tableName;
|
|
set<LogicalPartition> partSet;
|
|
partitionByValue_common(args, msg, tableName, partSet, "calDropPartitionsByValue");
|
|
|
|
if (!msg.empty())
|
|
{
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, msg.c_str());
|
|
return result;
|
|
}
|
|
|
|
msg = ha_mcs_impl_droppartitions_(tableName, partSet);
|
|
|
|
memcpy(result, msg.c_str(), msg.length());
|
|
*length = msg.length();
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* CalDisablePartitionsByValue
|
|
*/
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
void caldisablepartitionsbyvalue_deinit(UDF_INIT* initid)
|
|
{
|
|
}
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
my_bool caldisablepartitionsbyvalue_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
|
|
{
|
|
bool err = false;
|
|
|
|
if (args->arg_count < 4 || args->arg_count > 5)
|
|
{
|
|
err = true;
|
|
}
|
|
else if (args->arg_count == 4)
|
|
{
|
|
if (args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT || args->arg_type[2] != STRING_RESULT)
|
|
err = true;
|
|
}
|
|
else if (args->arg_count == 5)
|
|
{
|
|
if (args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT ||
|
|
args->arg_type[2] != STRING_RESULT || args->arg_type[3] != STRING_RESULT || args->arg_type[4] != STRING_RESULT)
|
|
err = true;
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
strcpy(message, "\nusage: CALDISABLEPARTITIONS (['schema'], 'table', 'column', 'min', 'max')");
|
|
return 1;
|
|
}
|
|
|
|
initid->maybe_null = 1;
|
|
initid->max_length = 255;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
const char* caldisablepartitionsbyvalue(UDF_INIT* initid, UDF_ARGS* args,
|
|
char* result, unsigned long* length,
|
|
char* is_null, char* error)
|
|
{
|
|
string msg;
|
|
set<LogicalPartition> partSet;
|
|
CalpontSystemCatalog::TableName tableName;
|
|
partitionByValue_common(args, msg, tableName, partSet, "calDisablePartitionsByValue");
|
|
|
|
if (!msg.empty())
|
|
{
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, msg.c_str());
|
|
return result;
|
|
}
|
|
|
|
msg = ha_mcs_impl_markpartitions_(tableName, partSet);
|
|
|
|
memcpy(result, msg.c_str(), msg.length());
|
|
*length = msg.length();
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* CalEnablePartitionsByValue
|
|
*/
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
void calenablepartitionsbyvalue_deinit(UDF_INIT* initid)
|
|
{
|
|
}
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
my_bool calenablepartitionsbyvalue_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
|
|
{
|
|
bool err = false;
|
|
|
|
if (args->arg_count < 4 || args->arg_count > 5)
|
|
{
|
|
err = true;
|
|
}
|
|
else if (args->arg_count == 4)
|
|
{
|
|
if (args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT || args->arg_type[2] != STRING_RESULT)
|
|
err = true;
|
|
}
|
|
else if (args->arg_count == 5)
|
|
{
|
|
if (args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT ||
|
|
args->arg_type[2] != STRING_RESULT || args->arg_type[3] != STRING_RESULT || args->arg_type[4] != STRING_RESULT)
|
|
err = true;
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
strcpy(message, "\nusage: CALENABLEPARTITIONSBYVALUE (['schema'], 'table', 'column', 'min', 'max')");
|
|
return 1;
|
|
}
|
|
|
|
initid->maybe_null = 1;
|
|
initid->max_length = 255;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
const char* calenablepartitionsbyvalue(UDF_INIT* initid, UDF_ARGS* args,
|
|
char* result, unsigned long* length,
|
|
char* is_null, char* error)
|
|
{
|
|
string msg;
|
|
set<LogicalPartition> partSet;
|
|
CalpontSystemCatalog::TableName tableName;
|
|
partitionByValue_common(args, msg, tableName, partSet, "calEnablePartitionsByValue");
|
|
|
|
if (!msg.empty())
|
|
{
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, msg.c_str());
|
|
return result;
|
|
}
|
|
|
|
msg = ha_mcs_impl_restorepartitions_(tableName, partSet);
|
|
|
|
memcpy(result, msg.c_str(), msg.length());
|
|
*length = msg.length();
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* CalShowPartitionsByValue
|
|
*/
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
my_bool calshowpartitionsbyvalue_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
|
|
{
|
|
bool err = false;
|
|
|
|
if (args->arg_count < 4 || args->arg_count > 5)
|
|
{
|
|
err = true;
|
|
}
|
|
else if (args->arg_count == 4)
|
|
{
|
|
if (args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT || args->arg_type[2] != STRING_RESULT)
|
|
err = true;
|
|
}
|
|
else if (args->arg_count == 5)
|
|
{
|
|
if (args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT ||
|
|
args->arg_type[2] != STRING_RESULT || args->arg_type[3] != STRING_RESULT || args->arg_type[4] != STRING_RESULT)
|
|
err = true;
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
strcpy(message, "\nusage: CALSHOWPARTITIONSBYVALUE (['schema'], 'table', 'column', 'min', 'max')");
|
|
return 1;
|
|
}
|
|
|
|
initid->maybe_null = 1;
|
|
initid->max_length = 255;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
void calshowpartitionsbyvalue_deinit(UDF_INIT* initid)
|
|
{
|
|
delete initid->ptr;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(dllexport)
|
|
#endif
|
|
const char* calshowpartitionsbyvalue(UDF_INIT* initid, UDF_ARGS* args,
|
|
char* result, unsigned long* length,
|
|
char* is_null, char* error)
|
|
{
|
|
DBRM em;
|
|
vector<struct EMEntry> entries;
|
|
vector<struct EMEntry>::iterator iter;
|
|
vector<struct EMEntry>::iterator end;
|
|
PartitionMap partMap;
|
|
PartitionMap::iterator mapit;
|
|
int32_t seqNum;
|
|
string schema, table, column;
|
|
CalpontSystemCatalog::ColType ct;
|
|
string errMsg;
|
|
int64_t startVal, endVal;
|
|
uint8_t rfMin = 0, rfMax = 0;
|
|
|
|
try
|
|
{
|
|
if (args->arg_count == 5)
|
|
{
|
|
schema = (char*)(args->args[0]);
|
|
table = (char*)(args->args[1]);
|
|
column = (char*)(args->args[2]);
|
|
}
|
|
else
|
|
{
|
|
if (current_thd->db.length)
|
|
{
|
|
schema = current_thd->db.str;
|
|
}
|
|
else
|
|
{
|
|
throw IDBExcept(ERR_PARTITION_NO_SCHEMA);
|
|
}
|
|
|
|
table = (char*)(args->args[0]);
|
|
column = (char*)(args->args[1]);
|
|
}
|
|
|
|
boost::shared_ptr<CalpontSystemCatalog> csc = CalpontSystemCatalog::makeCalpontSystemCatalog(tid2sid(current_thd->thread_id));
|
|
csc->identity(CalpontSystemCatalog::FE);
|
|
CalpontSystemCatalog::TableColName tcn = make_tcn(schema, table, column);
|
|
OID_t oid = csc->lookupOID(tcn);
|
|
ct = csc->colType(oid);
|
|
|
|
if (oid == -1)
|
|
{
|
|
Message::Args args;
|
|
args.add("'" + schema + string(".") + table + string(".") + column + "'");
|
|
throw IDBExcept(ERR_TABLE_NOT_IN_CATALOG, args);
|
|
}
|
|
|
|
// check casual partition data type
|
|
if (!CP_type(ct))
|
|
{
|
|
Message::Args args;
|
|
args.add(name(ct));
|
|
args.add("calShowPartitionsByValue");
|
|
throw IDBExcept(ERR_PARTITION_BY_RANGE, args);
|
|
}
|
|
|
|
if (args->arg_count == 4)
|
|
{
|
|
if (!args->args[2])
|
|
{
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
startVal = 0;
|
|
}
|
|
else
|
|
{
|
|
startVal = numeric_limits<int64_t>::min();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
startVal = IDB_format((char*) args->args[2], ct, rfMin);
|
|
}
|
|
|
|
if (!args->args[3])
|
|
{
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
endVal = static_cast<int64_t>(numeric_limits<uint64_t>::max());
|
|
}
|
|
else
|
|
{
|
|
endVal = numeric_limits<int64_t>::max();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
endVal = IDB_format((char*) args->args[3], ct, rfMax);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!args->args[3])
|
|
{
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
startVal = 0;
|
|
}
|
|
else
|
|
{
|
|
startVal = numeric_limits<int64_t>::min();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
startVal = IDB_format((char*) args->args[3], ct, rfMin);
|
|
}
|
|
|
|
if (!args->args[4])
|
|
{
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
endVal = static_cast<int64_t>(numeric_limits<uint64_t>::max());
|
|
}
|
|
else
|
|
{
|
|
endVal = numeric_limits<int64_t>::max();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
endVal = IDB_format((char*) args->args[4], ct, rfMax);
|
|
}
|
|
}
|
|
|
|
CHECK(em.getExtents(oid, entries, false, false, true));
|
|
|
|
if (entries.size() > 0)
|
|
{
|
|
iter = entries.begin();
|
|
end = entries.end();
|
|
LogicalPartition logicalPartNum;
|
|
|
|
for (; iter != end; ++iter)
|
|
{
|
|
PartitionInfo partInfo;
|
|
logicalPartNum.dbroot = (*iter).dbRoot;
|
|
logicalPartNum.pp = (*iter).partitionNum;
|
|
logicalPartNum.seg = (*iter).segmentNum;
|
|
|
|
if (iter->status == EXTENTOUTOFSERVICE)
|
|
partInfo.status |= ET_DISABLED;
|
|
|
|
mapit = partMap.find(logicalPartNum);
|
|
int state = em.getExtentMaxMin(iter->range.start, partInfo.max, partInfo.min, seqNum);
|
|
|
|
// char column order swap
|
|
if ((ct.colDataType == CalpontSystemCatalog::CHAR && ct.colWidth <= 8) ||
|
|
(ct.colDataType == CalpontSystemCatalog::VARCHAR && ct.colWidth <= 7))
|
|
{
|
|
partInfo.max = uint64ToStr(partInfo.max);
|
|
partInfo.min = uint64ToStr(partInfo.min);
|
|
}
|
|
|
|
if (mapit == partMap.end())
|
|
{
|
|
if (state != CP_VALID)
|
|
partInfo.status |= CPINVALID;
|
|
|
|
partMap[logicalPartNum] = partInfo;
|
|
}
|
|
else
|
|
{
|
|
if (mapit->second.status & CPINVALID)
|
|
continue;
|
|
|
|
if (isUnsigned(ct.colDataType))
|
|
{
|
|
mapit->second.min =
|
|
(static_cast<uint64_t>(partInfo.min) < static_cast<uint64_t>(mapit->second.min) ? partInfo.min : mapit->second.min);
|
|
mapit->second.max =
|
|
(static_cast<uint64_t>(partInfo.max) > static_cast<uint64_t>(mapit->second.max) ? partInfo.max : mapit->second.max);
|
|
}
|
|
else
|
|
{
|
|
mapit->second.min = (partInfo.min < mapit->second.min ? partInfo.min : mapit->second.min);
|
|
mapit->second.max = (partInfo.max > mapit->second.max ? partInfo.max : mapit->second.max);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (logging::QueryDataExcept& ex)
|
|
{
|
|
Message::Args args;
|
|
args.add(ex.what());
|
|
errMsg = IDBErrorInfo::instance()->errorMsg(ERR_INVALID_FUNC_ARGUMENT, args);
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, (char*)errMsg.c_str());
|
|
return result;
|
|
}
|
|
catch (IDBExcept& ex)
|
|
{
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, ex.what());
|
|
return result;
|
|
}
|
|
catch (...)
|
|
{
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, "Error occured when calling CALSHOWPARTITIONS");
|
|
return result;
|
|
}
|
|
|
|
// create a set of partInfo for sorting.
|
|
bool noPartFound = true;
|
|
ostringstream output;
|
|
|
|
for (mapit = partMap.begin(); mapit != partMap.end(); ++mapit)
|
|
{
|
|
// @bug 4595. check empty/null case
|
|
if (!(mapit->second.status & CPINVALID) && mapit->second.min >= startVal && mapit->second.max <= endVal &&
|
|
!(mapit->second.min == numeric_limits<int64_t>::max() && mapit->second.max == numeric_limits<int64_t>::min()))
|
|
{
|
|
if (rfMin == ROUND_POS && mapit->second.min == startVal)
|
|
continue;
|
|
|
|
if (rfMax == ROUND_NEG && mapit->second.max == endVal)
|
|
continue;
|
|
|
|
// print header
|
|
if (noPartFound)
|
|
{
|
|
output.setf(ios::left, ios::adjustfield);
|
|
output << setw(10) << "Part#"
|
|
<< setw(30) << "Min"
|
|
<< setw(30) << "Max" << "Status";
|
|
}
|
|
|
|
noPartFound = false;
|
|
|
|
// print part info
|
|
ostringstream oss;
|
|
oss << mapit->first;
|
|
output << "\n " << setw(10) << oss.str();
|
|
|
|
if (mapit->second.status & CPINVALID)
|
|
{
|
|
output << setw(30) << "N/A" << setw(30) << "N/A";
|
|
}
|
|
else
|
|
{
|
|
if ((isUnsigned(ct.colDataType)))
|
|
{
|
|
if (static_cast<uint64_t>(mapit->second.min) > static_cast<uint64_t>(mapit->second.max))
|
|
output << setw(30) << "Empty/Null" << setw(30) << "Empty/Null";
|
|
else
|
|
output << setw(30) << format(mapit->second.min, ct) << setw(30) << format(mapit->second.max, ct);
|
|
}
|
|
else
|
|
{
|
|
if (mapit->second.min > mapit->second.max)
|
|
output << setw(30) << "Empty/Null" << setw(30) << "Empty/Null";
|
|
else
|
|
output << setw(30) << format(mapit->second.min, ct) << setw(30) << format(mapit->second.max, ct);
|
|
}
|
|
}
|
|
|
|
if (mapit->second.status & ET_DISABLED)
|
|
output << "Disabled";
|
|
else
|
|
output << "Enabled";
|
|
}
|
|
}
|
|
|
|
if (noPartFound)
|
|
{
|
|
errMsg = IDBErrorInfo::instance()->errorMsg(WARN_NO_PARTITION_FOUND);
|
|
current_thd->get_stmt_da()->set_overwrite_status(true);
|
|
current_thd->raise_error_printf(ER_INTERNAL_ERROR, errMsg.c_str());
|
|
return result;
|
|
}
|
|
|
|
// use our own buffer to make sure it fits.
|
|
initid->ptr = new char[output.str().length() + 1];
|
|
memcpy(initid->ptr, output.str().c_str(), output.str().length());
|
|
*length = output.str().length();
|
|
return initid->ptr;
|
|
}
|
|
|
|
}
|
|
|
|
}
|