<commit_before>/*-------------------------------------------------------------------------
 *
 * expr_transformer.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 *-------------------------------------------------------------------------
 */

#include <unordered_map>

#include "nodes/pprint.h"
#include "utils/rel.h"
#include "utils/lsyscache.h"
#include "parser/parsetree.h"

#include "backend/bridge/dml/tuple/tuple_transformer.h"
#include "backend/bridge/dml/expr/pg_func_map.h"
#include "backend/bridge/dml/expr/expr_transformer.h"
#include "backend/bridge/dml/executor/plan_executor.h"
#include "backend/common/logger.h"
#include "backend/common/value.h"
#include "backend/common/value_factory.h"
#include "backend/expression/expression_util.h"

namespace peloton {
namespace bridge {


expression::AbstractExpression*
ReMapPgFunc(Oid pg_func_id,
            expression::AbstractExpression* lc,
            expression::AbstractExpression* rc);

extern std::unordered_map<Oid, peloton::ExpressionType> pg_func_map;

void ExprTransformer::PrintPostgressExprTree(const ExprState* expr_state,
                                             std::string prefix) {
  auto tag = nodeTag(expr_state->expr);

  /* TODO Not complete.
   * Not all ExprState has a child / children list,
   * so it would take some multiplexing to print it recursively here.
   */
  LOG_INFO("%u ", tag);
}

/**
 * @brief Transform a ExprState tree (Postgres) to a AbstractExpression tree (Peloton) recursively.
 */
expression::AbstractExpression* ExprTransformer::TransformExpr(
    const ExprState* expr_state) {

  if(!expr_state)
    return nullptr;

  /* Special case:
   * Input is a list of expressions.
   * Transform it to a conjunction tree.
   */
  if(expr_state->type == T_List) {
    return TransformList(expr_state);
  }

  expression::AbstractExpression* peloton_expr = nullptr;

  switch (nodeTag(expr_state->expr)) {
    case T_Const:
      peloton_expr = TransformConst(expr_state);
      break;

    case T_OpExpr:
      peloton_expr = TransformOp(expr_state);
      break;

    case T_Var:
      peloton_expr = TransformVar(expr_state);
      break;

    case T_BoolExpr:
      peloton_expr = TransformBool(expr_state);
      break;

    case T_Param:
      peloton_expr = TransformParam(expr_state);
      break;

    case T_RelabelType:
      peloton_expr = TransformRelabelType(expr_state);
      break;

    case T_FuncExpr:
      peloton_expr = TransformFunc(expr_state);
      break;

    default:
      LOG_ERROR("Unsupported Postgres Expr type: %u (see 'nodes.h')\n",
                nodeTag(expr_state->expr));
  }

  return peloton_expr;
}

bool ExprTransformer::CleanExprTree(expression::AbstractExpression* root) {

  // AbstractExpression's destructor already handles deleting children
  delete root;

  return true;
}

expression::AbstractExpression* ExprTransformer::TransformConst(
    const ExprState* es) {

  auto const_expr = reinterpret_cast<const Const*>(es->expr);

  Value value;

  if (const_expr->constisnull) {  // Constant is null
    value = ValueFactory::GetNullValue();
  }
  else if(const_expr->constbyval){  // non null
    value = TupleTransformer::GetValue(const_expr->constvalue,
                                       const_expr->consttype);
  }
  else if(const_expr->constlen == -1) {
    LOG_INFO("Probably handing a string constant \n");
    value = TupleTransformer::GetValue(const_expr->constvalue,
                                       const_expr->consttype);
  }
  else {
    LOG_ERROR("Unknown Const profile: constlen = %d , constbyval = %d, constvalue = %lu \n",
              const_expr->constlen, const_expr->constbyval, (long unsigned)const_expr->constvalue);
  }

  LOG_INFO("Const : ");
  std::cout << value << std::endl;

  // A Const Expr has no children.
  return expression::ConstantValueFactory(value);
}


expression::AbstractExpression* ExprTransformer::TransformOp(
    const ExprState* es) {

  LOG_INFO("Transform Op \n");

  auto op_expr = reinterpret_cast<const OpExpr*>(es->expr);
  auto func_state = reinterpret_cast<const FuncExprState*>(es);

  assert(op_expr->opfuncid != 0); // Hopefully it has been filled in by PG planner
  assert(list_length(func_state->args) <= 2);   // Hopefully it has at most two parameters

  expression::AbstractExpression* lc = nullptr;
  expression::AbstractExpression* rc = nullptr;

  // Add function arguments as children
  int i = 0;
  ListCell   *arg;
  foreach(arg, func_state->args)
  {
    ExprState  *argstate = (ExprState *) lfirst(arg);

    if(i == 0)
      lc = TransformExpr(argstate);
    else if(i == 1)
      rc = TransformExpr(argstate);
    else
      break; // skip >2 arguments

    i++;
  }

  return ReMapPgFunc(op_expr->opfuncid, lc, rc);
}

expression::AbstractExpression* ExprTransformer::TransformVar(
    const ExprState* es) {

  // Var expr only needs default ES
  auto var_expr = reinterpret_cast<const Var*>(es->expr);

  assert(var_expr->varattno != InvalidAttrNumber);

  oid_t tuple_idx = (var_expr->varno == INNER_VAR ? 1 : 0);  // Seems reasonable, c.f. ExecEvalScalarVarFast()
  oid_t value_idx = static_cast<oid_t>(var_expr->varattno - 1); // Damnit attno is 1-index

  LOG_INFO("tuple_idx = %u , value_idx = %u \n", tuple_idx, value_idx);

  // TupleValue expr has no children.
  return expression::TupleValueFactory(tuple_idx, value_idx);

}

expression::AbstractExpression* ExprTransformer::TransformBool(
    const ExprState* es) {

  auto bool_expr = reinterpret_cast<const BoolExpr*>(es->expr);
  auto bool_state = reinterpret_cast<const BoolExprState*>(es);

  auto bool_op = bool_expr->boolop;


  /*
   * AND and OR can take >=2 arguments,
   * while NOT should take only one.
   */
  assert(bool_state->args);
  assert(bool_op != NOT_EXPR || list_length(bool_state->args) == 1);
  assert(bool_op == NOT_EXPR || list_length(bool_state->args) >= 2);

  auto args = bool_state->args;

  switch(bool_op){

    case AND_EXPR:
      LOG_INFO("Bool AND list \n");
      return TransformList(reinterpret_cast<const ExprState*>(args), EXPRESSION_TYPE_CONJUNCTION_AND);

    case OR_EXPR:
      LOG_INFO("Bool OR list \n");
      return TransformList(reinterpret_cast<const ExprState*>(args), EXPRESSION_TYPE_CONJUNCTION_OR);

    case NOT_EXPR:
    {
      LOG_INFO("Bool NOT \n");
      auto child_es = reinterpret_cast<const ExprState*>(lfirst(list_head(args)));
      auto child = TransformExpr(child_es);
      return expression::OperatorFactory(EXPRESSION_TYPE_OPERATOR_NOT, child, nullptr);
    }

    default:
      LOG_ERROR("Unrecognized BoolExpr : %u", bool_op);
  }

  return nullptr;
}

expression::AbstractExpression* ExprTransformer::TransformParam(const ExprState *es) {

  auto param_expr = reinterpret_cast<const Param*>(es->expr);

  switch (param_expr->paramkind) {
    case PARAM_EXTERN:
      LOG_INFO("Handle EXTREN PARAM");
      return expression::ParameterValueFactory(param_expr->paramid - 1); // 1 indexed
      break;
    default:
      LOG_ERROR("Unrecognized param kind %d", param_expr->paramkind);
      break;
  }

  return nullptr;
}


expression::AbstractExpression* ExprTransformer::TransformRelabelType(const ExprState *es) {
  auto state = reinterpret_cast<const GenericExprState*>(es);
  auto expr = reinterpret_cast<const RelabelType *>(es->expr);
  auto child_state = state->arg;
  auto child_expr = expr->arg;

  assert(expr->xpr.type == T_RelabelType);

  LOG_INFO("child is of type %d, %d", child_expr->type, child_state->type);
  LOG_INFO("%d, %d", expr->resulttype, expr->relabelformat);
  expression::AbstractExpression *child = ExprTransformer::TransformExpr(child_state);

  //TODO: not implemented yet


  return child;
}

expression::AbstractExpression* ExprTransformer::TransformFunc(const ExprState *es) {
  auto state = reinterpret_cast<const FuncExprState*>(es);<commit_msg>add support for RelabelType expr<commit_after>/*-------------------------------------------------------------------------
 *
 * expr_transformer.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 *-------------------------------------------------------------------------
 */

#include <unordered_map>

#include "nodes/pprint.h"
#include "utils/rel.h"
#include "utils/lsyscache.h"
#include "parser/parsetree.h"

#include "backend/bridge/dml/tuple/tuple_transformer.h"
#include "backend/bridge/dml/expr/pg_func_map.h"
#include "backend/bridge/dml/expr/expr_transformer.h"
#include "backend/bridge/dml/executor/plan_executor.h"
#include "backend/common/logger.h"
#include "backend/common/value.h"
#include "backend/common/value_factory.h"
#include "backend/expression/expression_util.h"

namespace peloton {
namespace bridge {


expression::AbstractExpression*
ReMapPgFunc(Oid pg_func_id,
            expression::AbstractExpression* lc,
            expression::AbstractExpression* rc);

extern std::unordered_map<Oid, peloton::ExpressionType> pg_func_map;

void ExprTransformer::PrintPostgressExprTree(const ExprState* expr_state,
                                             std::string prefix) {
  auto tag = nodeTag(expr_state->expr);

  /* TODO Not complete.
   * Not all ExprState has a child / children list,
   * so it would take some multiplexing to print it recursively here.
   */
  LOG_INFO("%u ", tag);
}

/**
 * @brief Transform a ExprState tree (Postgres) to a AbstractExpression tree (Peloton) recursively.
 */
expression::AbstractExpression* ExprTransformer::TransformExpr(
    const ExprState* expr_state) {

  if(!expr_state)
    return nullptr;

  /* Special case:
   * Input is a list of expressions.
   * Transform it to a conjunction tree.
   */
  if(expr_state->type == T_List) {
    return TransformList(expr_state);
  }

  expression::AbstractExpression* peloton_expr = nullptr;

  switch (nodeTag(expr_state->expr)) {
    case T_Const:
      peloton_expr = TransformConst(expr_state);
      break;

    case T_OpExpr:
      peloton_expr = TransformOp(expr_state);
      break;

    case T_Var:
      peloton_expr = TransformVar(expr_state);
      break;

    case T_BoolExpr:
      peloton_expr = TransformBool(expr_state);
      break;

    case T_Param:
      peloton_expr = TransformParam(expr_state);
      break;

    case T_RelabelType:
      peloton_expr = TransformRelabelType(expr_state);
      break;

    case T_FuncExpr:
      peloton_expr = TransformFunc(expr_state);
      break;

    default:
      LOG_ERROR("Unsupported Postgres Expr type: %u (see 'nodes.h')\n",
                nodeTag(expr_state->expr));
  }

  return peloton_expr;
}

bool ExprTransformer::CleanExprTree(expression::AbstractExpression* root) {

  // AbstractExpression's destructor already handles deleting children
  delete root;

  return true;
}

expression::AbstractExpression* ExprTransformer::TransformConst(
    const ExprState* es) {

  auto const_expr = reinterpret_cast<const Const*>(es->expr);

  Value value;

  if (const_expr->constisnull) {  // Constant is null
    value = ValueFactory::GetNullValue();
  }
  else if(const_expr->constbyval){  // non null
    value = TupleTransformer::GetValue(const_expr->constvalue,
                                       const_expr->consttype);
  }
  else if(const_expr->constlen == -1) {
    LOG_INFO("Probably handing a string constant \n");
    value = TupleTransformer::GetValue(const_expr->constvalue,
                                       const_expr->consttype);
  }
  else {
    LOG_ERROR("Unknown Const profile: constlen = %d , constbyval = %d, constvalue = %lu \n",
              const_expr->constlen, const_expr->constbyval, (long unsigned)const_expr->constvalue);
  }

  LOG_INFO("Const : ");
  std::cout << value << std::endl;

  // A Const Expr has no children.
  return expression::ConstantValueFactory(value);
}


expression::AbstractExpression* ExprTransformer::TransformOp(
    const ExprState* es) {

  LOG_INFO("Transform Op \n");

  auto op_expr = reinterpret_cast<const OpExpr*>(es->expr);
  auto func_state = reinterpret_cast<const FuncExprState*>(es);

  assert(op_expr->opfuncid != 0); // Hopefully it has been filled in by PG planner
  assert(list_length(func_state->args) <= 2);   // Hopefully it has at most two parameters

  expression::AbstractExpression* lc = nullptr;
  expression::AbstractExpression* rc = nullptr;

  // Add function arguments as children
  int i = 0;
  ListCell   *arg;
  foreach(arg, func_state->args)
  {
    ExprState  *argstate = (ExprState *) lfirst(arg);

    if(i == 0)
      lc = TransformExpr(argstate);
    else if(i == 1)
      rc = TransformExpr(argstate);
    else
      break; // skip >2 arguments

    i++;
  }

  return ReMapPgFunc(op_expr->opfuncid, lc, rc);
}

expression::AbstractExpression* ExprTransformer::TransformVar(
    const ExprState* es) {

  // Var expr only needs default ES
  auto var_expr = reinterpret_cast<const Var*>(es->expr);

  assert(var_expr->varattno != InvalidAttrNumber);

  oid_t tuple_idx = (var_expr->varno == INNER_VAR ? 1 : 0);  // Seems reasonable, c.f. ExecEvalScalarVarFast()
  oid_t value_idx = static_cast<oid_t>(var_expr->varattno - 1); // Damnit attno is 1-index

  LOG_INFO("tuple_idx = %u , value_idx = %u \n", tuple_idx, value_idx);

  // TupleValue expr has no children.
  return expression::TupleValueFactory(tuple_idx, value_idx);

}

expression::AbstractExpression* ExprTransformer::TransformBool(
    const ExprState* es) {

  auto bool_expr = reinterpret_cast<const BoolExpr*>(es->expr);
  auto bool_state = reinterpret_cast<const BoolExprState*>(es);

  auto bool_op = bool_expr->boolop;


  /*
   * AND and OR can take >=2 arguments,
   * while NOT should take only one.
   */
  assert(bool_state->args);
  assert(bool_op != NOT_EXPR || list_length(bool_state->args) == 1);
  assert(bool_op == NOT_EXPR || list_length(bool_state->args) >= 2);

  auto args = bool_state->args;

  switch(bool_op){

    case AND_EXPR:
      LOG_INFO("Bool AND list \n");
      return TransformList(reinterpret_cast<const ExprState*>(args), EXPRESSION_TYPE_CONJUNCTION_AND);

    case OR_EXPR:
      LOG_INFO("Bool OR list \n");
      return TransformList(reinterpret_cast<const ExprState*>(args), EXPRESSION_TYPE_CONJUNCTION_OR);

    case NOT_EXPR:
    {
      LOG_INFO("Bool NOT \n");
      auto child_es = reinterpret_cast<const ExprState*>(lfirst(list_head(args)));
      auto child = TransformExpr(child_es);
      return expression::OperatorFactory(EXPRESSION_TYPE_OPERATOR_NOT, child, nullptr);
    }

    default:
      LOG_ERROR("Unrecognized BoolExpr : %u", bool_op);
  }

  return nullptr;
}

expression::AbstractExpression* ExprTransformer::TransformParam(const ExprState *es) {

  auto param_expr = reinterpret_cast<const Param*>(es->expr);

  switch (param_expr->paramkind) {
    case PARAM_EXTERN:
      LOG_INFO("Handle EXTREN PARAM");
      return expression::ParameterValueFactory(param_expr->paramid - 1); // 1 indexed
      break;
    default:
      LOG_ERROR("Unrecognized param kind %d", param_expr->paramkind);
      break;
  }

  return nullptr;
}


expression::AbstractExpression* ExprTransformer::TransformRelabelType(const ExprState *es) {
  auto state = reinterpret_cast<const GenericExprState*>(es);
  auto expr = reinterpret_cast<const RelabelType *>(es->expr);
  auto child_state = state->arg;

  assert(expr->relabelformat == COERCE_IMPLICIT_CAST);

  LOG_INFO("Handle relabel as %d", expr->resulttype);
  expression::AbstractExpression *child = ExprTransformer::TransformExpr(child_state);

  PostgresValueType type = static_cast<PostgresValueType>(expr->resulttype);

  return expression::CastFactory(type, child);
}

expression::AbstractExpression* ExprTransformer::TransformFunc(const ExprState *es) {
  auto state = reinterpret_cast<const FuncExprState*>(es);
{'fraction_non_alphanumeric': 0.13413858868404324, 'fraction_numerical': 0.0025429116338207248, 'mean_word_length': 3.5256041426927505, 'pattern_counts': {'":': 0, '<': 46, '<?xml version=': 0, '>': 123, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3131371', 'n_tokens_mistral': 5048, 'n_tokens_neox': 4817, 'n_words': 1071}