You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-11-03 17:13:17 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			491 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			491 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#define PREFER_MY_CONFIG_H
 | 
						|
#include <my_config.h>
 | 
						|
// #include <cmath>
 | 
						|
#include <iostream>
 | 
						|
#include <sstream>
 | 
						|
 | 
						|
#include "idb_mysql.h"
 | 
						|
 | 
						|
#include "errorids.h"
 | 
						|
#include "idberrorinfo.h"
 | 
						|
using namespace logging;
 | 
						|
 | 
						|
#include "pseudocolumn.h"
 | 
						|
#include "functioncolumn.h"
 | 
						|
#include "constantcolumn.h"
 | 
						|
using namespace execplan;
 | 
						|
 | 
						|
#include "functor.h"
 | 
						|
#include "functor_str.h"
 | 
						|
 | 
						|
#include "ha_mcs.h"
 | 
						|
#include "ha_mcs_impl_if.h"
 | 
						|
#include "ha_mcs_sysvars.h"
 | 
						|
using namespace cal_impl_if;
 | 
						|
using namespace std;
 | 
						|
 | 
						|
namespace
 | 
						|
{
 | 
						|
/*******************************************************************************
 | 
						|
 * Pseudo column connector interface
 | 
						|
 *
 | 
						|
 * idbdbroot
 | 
						|
 * idbpm
 | 
						|
 * idbextentrelativerid
 | 
						|
 * idbsegmentdir
 | 
						|
 * idbsegment
 | 
						|
 * idbpartition
 | 
						|
 * idbextentmin
 | 
						|
 * idbextentmax
 | 
						|
 * idbextentid
 | 
						|
 * idbblockid
 | 
						|
 *
 | 
						|
 * All the pseudo column functions are only executed in InfiniDB.
 | 
						|
 */
 | 
						|
 | 
						|
void bailout(char* error, const string& funcName)
 | 
						|
{
 | 
						|
  string errMsg = IDBErrorInfo::instance()->errorMsg(ERR_PSEUDOCOL_IDB_ONLY, funcName);
 | 
						|
  current_thd->get_stmt_da()->set_overwrite_status(true);
 | 
						|
  current_thd->raise_error_printf(ER_INTERNAL_ERROR, errMsg.c_str());
 | 
						|
  *error = 1;
 | 
						|
}
 | 
						|
 | 
						|
int64_t idblocalpm()
 | 
						|
{
 | 
						|
  if (get_fe_conn_info_ptr() == NULL)
 | 
						|
  {
 | 
						|
    set_fe_conn_info_ptr((void*)new cal_connection_info());
 | 
						|
    thd_set_ha_data(current_thd, mcs_hton, get_fe_conn_info_ptr());
 | 
						|
  }
 | 
						|
 | 
						|
  cal_connection_info* ci = reinterpret_cast<cal_connection_info*>(get_fe_conn_info_ptr());
 | 
						|
 | 
						|
  if (ci->localPm == -1)
 | 
						|
  {
 | 
						|
    string module = ClientRotator::getModule();
 | 
						|
 | 
						|
    if (module.size() >= 3 && (module[0] == 'p' || module[0] == 'P'))
 | 
						|
      ci->localPm = atol(module.c_str() + 2);
 | 
						|
    else
 | 
						|
      ci->localPm = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return ci->localPm;
 | 
						|
}
 | 
						|
 | 
						|
extern "C"
 | 
						|
{
 | 
						|
  /**
 | 
						|
   * IDBDBROOT
 | 
						|
   */
 | 
						|
  my_bool idbdbroot_init(UDF_INIT* /*initid*/, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbdbroot() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbdbroot_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  long long idbdbroot(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbdbroot");
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBPM
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idbpm_init(UDF_INIT* /*initid*/, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbpm() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbpm_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  long long idbpm(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbpm");
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBEXTENTRELATIVERID
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idbextentrelativerid_init(UDF_INIT* /*initid*/, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbextentrelativerid() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbextentrelativerid_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  long long idbextentrelativerid(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbextentrelativerid");
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBBLOCKID
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idbblockid_init(UDF_INIT* /*initid*/, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbblockid() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbblockid_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  long long idbblockid(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbblockid");
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBEXTENTID
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idbextentid_init(UDF_INIT* /*initid*/, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbextentid() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbextentid_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  long long idbextentid(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbextentid");
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBSEGMENT
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idbsegment_init(UDF_INIT* /*initid*/, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbsegment() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbsegment_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  long long idbsegment(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbsegment");
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBSEGMENTDIR
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idbsegmentdir_init(UDF_INIT* /*initid*/, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbsegmentdir() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbsegmentdir_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  long long idbsegmentdir(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbsegmentdir");
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBPARTITION
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idbpartition_init(UDF_INIT* /*initid*/, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbpartition() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbpartition_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  const char* idbpartition(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* result, unsigned long* /*length*/,
 | 
						|
                           char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbpartition");
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBEXTENTMIN
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idbextentmin_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbpm() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    initid->maybe_null = 1;
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbextentmin_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  const char* idbextentmin(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* result, unsigned long* /*length*/,
 | 
						|
                           char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbextentmin");
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBEXTENTMAX
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idbextentmax_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 1)
 | 
						|
    {
 | 
						|
      strcpy(message, "idbextentmax() requires one argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    initid->maybe_null = 1;
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idbextentmax_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  const char* idbextentmax(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* result, unsigned long* /*length*/,
 | 
						|
                           char* /*is_null*/, char* error)
 | 
						|
  {
 | 
						|
    bailout(error, "idbextentmax");
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * IDBLOCALPM
 | 
						|
   */
 | 
						|
 | 
						|
  my_bool idblocalpm_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
 | 
						|
  {
 | 
						|
    if (args->arg_count != 0)
 | 
						|
    {
 | 
						|
      strcpy(message, "idblocalpm() should take no argument");
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    initid->maybe_null = 1;
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  void idblocalpm_deinit(UDF_INIT* /*initid*/)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  long long idblocalpm(UDF_INIT* /*initid*/, UDF_ARGS* /*args*/, char* is_null, char* /*error*/)
 | 
						|
  {
 | 
						|
    longlong localpm = idblocalpm();
 | 
						|
 | 
						|
    if (localpm == 0)
 | 
						|
      *is_null = 1;
 | 
						|
 | 
						|
    return localpm;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
namespace cal_impl_if
 | 
						|
{
 | 
						|
ReturnedColumn* nullOnError(gp_walk_info& gwi, string& funcName)
 | 
						|
{
 | 
						|
  gwi.fatalParseError = true;
 | 
						|
  gwi.parseErrorText =
 | 
						|
      logging::IDBErrorInfo::instance()->errorMsg(logging::ERR_PSEUDOCOL_WRONG_ARG, funcName);
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t isPseudoColumn(string funcName)
 | 
						|
{
 | 
						|
  return execplan::PseudoColumn::pseudoNameToType(funcName);
 | 
						|
}
 | 
						|
 | 
						|
execplan::ReturnedColumn* buildPseudoColumn(Item* item, gp_walk_info& gwi, bool& /*nonSupport*/,
 | 
						|
                                            uint32_t pseudoType)
 | 
						|
{
 | 
						|
  if (get_fe_conn_info_ptr() == NULL)
 | 
						|
  {
 | 
						|
    set_fe_conn_info_ptr((void*)new cal_connection_info());
 | 
						|
    thd_set_ha_data(current_thd, mcs_hton, get_fe_conn_info_ptr());
 | 
						|
  }
 | 
						|
 | 
						|
  cal_connection_info* ci = reinterpret_cast<cal_connection_info*>(get_fe_conn_info_ptr());
 | 
						|
 | 
						|
  Item_func* ifp = (Item_func*)item;
 | 
						|
 | 
						|
  // idblocalpm is replaced by constant
 | 
						|
  if (pseudoType == PSEUDO_LOCALPM)
 | 
						|
  {
 | 
						|
    int64_t localPm = idblocalpm();
 | 
						|
    ConstantColumn* cc;
 | 
						|
 | 
						|
    if (localPm)
 | 
						|
      cc = new ConstantColumn(localPm);
 | 
						|
    else
 | 
						|
      cc = new ConstantColumn("", ConstantColumn::NULLDATA);
 | 
						|
    cc->timeZone(gwi.timeZone);
 | 
						|
 | 
						|
    cc->alias(ifp->full_name() ? ifp->full_name() : "");
 | 
						|
    return cc;
 | 
						|
  }
 | 
						|
 | 
						|
  // convert udf item to pseudocolumn item.
 | 
						|
  // adjust result type
 | 
						|
  // put arg col to column map
 | 
						|
  string funcName = ifp->func_name();
 | 
						|
 | 
						|
  if (ifp->argument_count() != 1 || !(ifp->arguments()) || !(ifp->arguments()[0]) ||
 | 
						|
      ifp->arguments()[0]->type() != Item::FIELD_ITEM)
 | 
						|
    return nullOnError(gwi, funcName);
 | 
						|
 | 
						|
  Item_field* field = (Item_field*)(ifp->arguments()[0]);
 | 
						|
 | 
						|
  // @todo rule out derive table
 | 
						|
  if (!field->field || !field->db_name.str || strlen(field->db_name.str) == 0)
 | 
						|
    return nullOnError(gwi, funcName);
 | 
						|
 | 
						|
  SimpleColumn* sc = buildSimpleColumn(field, gwi);
 | 
						|
 | 
						|
  if (!sc)
 | 
						|
    return nullOnError(gwi, funcName);
 | 
						|
 | 
						|
  if ((pseudoType == PSEUDO_EXTENTMIN || pseudoType == PSEUDO_EXTENTMAX) &&
 | 
						|
      (sc->colType().colDataType == CalpontSystemCatalog::VARBINARY ||
 | 
						|
       (sc->colType().colDataType == CalpontSystemCatalog::TEXT) ||
 | 
						|
       (sc->colType().colDataType == CalpontSystemCatalog::VARCHAR && sc->colType().colWidth > 7) ||
 | 
						|
       (sc->colType().colDataType == CalpontSystemCatalog::CHAR && sc->colType().colWidth > 8)))
 | 
						|
    return nullOnError(gwi, funcName);
 | 
						|
 | 
						|
  // put arg col to column map
 | 
						|
  if (gwi.clauseType == SELECT || gwi.clauseType == GROUP_BY)  // select clause
 | 
						|
  {
 | 
						|
    SRCP srcp(sc);
 | 
						|
    gwi.columnMap.insert(CalpontSelectExecutionPlan::ColumnMap::value_type(sc->columnName(), srcp));
 | 
						|
    gwi.tableMap[make_aliastable(sc->schemaName(), sc->tableName(), sc->tableAlias(), sc->isColumnStore())] =
 | 
						|
        make_pair(1, field->cached_table);
 | 
						|
  }
 | 
						|
  else if (!gwi.rcWorkStack.empty())
 | 
						|
  {
 | 
						|
    gwi.rcWorkStack.pop();
 | 
						|
  }
 | 
						|
 | 
						|
  if (pseudoType == PSEUDO_PARTITION)
 | 
						|
  {
 | 
						|
    // parms: psueducolumn dbroot, segmentdir, segment
 | 
						|
    SPTP sptp;
 | 
						|
    FunctionColumn* fc = new FunctionColumn(funcName);
 | 
						|
    funcexp::FunctionParm parms;
 | 
						|
    PseudoColumn* dbroot = new PseudoColumn(*sc, PSEUDO_DBROOT);
 | 
						|
    sptp.reset(new ParseTree(dbroot));
 | 
						|
    parms.push_back(sptp);
 | 
						|
    PseudoColumn* pp = new PseudoColumn(*sc, PSEUDO_SEGMENTDIR);
 | 
						|
    sptp.reset(new ParseTree(pp));
 | 
						|
    parms.push_back(sptp);
 | 
						|
    PseudoColumn* seg = new PseudoColumn(*sc, PSEUDO_SEGMENT);
 | 
						|
    sptp.reset(new ParseTree(seg));
 | 
						|
    parms.push_back(sptp);
 | 
						|
    fc->functionParms(parms);
 | 
						|
    fc->expressionId(ci->expressionId++);
 | 
						|
    fc->timeZone(gwi.timeZone);
 | 
						|
 | 
						|
    // string result type
 | 
						|
    CalpontSystemCatalog::ColType ct;
 | 
						|
    ct.colDataType = CalpontSystemCatalog::VARCHAR;
 | 
						|
    ct.colWidth = 256;
 | 
						|
    fc->resultType(ct);
 | 
						|
 | 
						|
    // operation type integer
 | 
						|
    funcexp::Func_idbpartition* idbpartition = new funcexp::Func_idbpartition();
 | 
						|
    fc->operationType(idbpartition->operationType(parms, fc->resultType()));
 | 
						|
    fc->alias(ifp->full_name() ? ifp->full_name() : "");
 | 
						|
    delete idbpartition;
 | 
						|
    return fc;
 | 
						|
  }
 | 
						|
 | 
						|
  PseudoColumn* pc = new PseudoColumn(*sc, pseudoType);
 | 
						|
 | 
						|
  // @bug5892. set alias for derived table column matching.
 | 
						|
  pc->alias(ifp->name.length ? ifp->name.str : "");
 | 
						|
  return pc;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace cal_impl_if
 |