Exemplo n.º 1
0
const planner::AbstractPlan *PlanTransformer::TransformAgg(
    const AggPlanState *plan_state) {
  // Alias all I need
  const Agg *agg = plan_state->agg_plan;
  auto numphases = plan_state->numphases;
  auto numaggs = plan_state->numaggs;
  auto targetlist = plan_state->ps_targetlist;
  auto qual = plan_state->ps_qual;
  auto peragg = plan_state->peragg;
  auto tupleDesc = plan_state->result_tupleDescriptor;
  auto aggstrategy = plan_state->agg_plan->aggstrategy;

  LOG_INFO("Number of Agg phases: %d \n", numphases);

  // When we'll have >1 phases?
  if (numphases != 1) return nullptr;

  /* Get project info */
  std::unique_ptr<const planner::ProjectInfo> proj_info(
      BuildProjectInfoFromTLSkipJunk(targetlist));
  LOG_INFO("proj_info : \n%s", proj_info->Debug().c_str());

  /* Get predicate */
  std::unique_ptr<const expression::AbstractExpression> predicate(
      BuildPredicateFromQual(qual));

  /* Get Aggregate terms */
  std::vector<planner::AggregatePlan::AggTerm> unique_agg_terms;

  LOG_INFO("Number of (unique) Agg nodes: %d \n", numaggs);
  for (int aggno = 0; aggno < numaggs; aggno++) {
    auto transfn_oid = peragg[aggno].transfn_oid;

    auto itr = peloton::bridge::kPgTransitFuncMap.find(transfn_oid);
    if (kPgFuncMap.end() == itr) {
      LOG_ERROR("Unmapped Transit function Id : %u\n", transfn_oid);
      return nullptr;
    }

    // We don't check whether the mapped exprtype is a valid aggregate type
    // here.
    PltFuncMetaInfo fn_meta = itr->second;
    // We only take the first argument as input to aggregator because
    // we don't have multi-argument aggregator in Peloton at the moment.
    // WARNING: there can be no arguments (e.g., COUNT(*))
    auto arguments = peragg[aggno].aggrefstate->args;
    expression::AbstractExpression *agg_expr = nullptr;
    if (arguments) {
      GenericExprState *gstate =
          (GenericExprState *)lfirst(list_head(arguments));
      LOG_INFO("Creating Agg Expr");
      agg_expr = ExprTransformer::TransformExpr(gstate->arg);
      LOG_INFO("Done creating Agg Expr");
    }

    /*
     * AggStatePerAggData.sortColIdx along with other related attributes
     * are used to handle ORDER BY and DISTINCT *within* aggregation.
     * E.g.,
     * SELECT count(DISTINCT x) ...
     * SELECT str_agg(y ORDER BY x) ...
     * Currently, we only handle the agg(DISTINCT x) case by
     * checking whether numDistinctCols > 0.
     * Note that numDistinctCols > 0 may be a necessary but not sufficient
     * condition for agg(DISTINCT x).
     */

    bool distinct = (peragg[aggno].numDistinctCols > 0);

    unique_agg_terms.emplace_back(fn_meta.exprtype, agg_expr, distinct);

    LOG_INFO(
        "Unique Agg # : %d , transfn_oid : %u\n , aggtype = %s \n expr = %s, "
        "numDistinctCols = %d",
        aggno, transfn_oid, ExpressionTypeToString(fn_meta.exprtype).c_str(),
        agg_expr ? agg_expr->Debug().c_str() : "<NULL>",
        peragg[aggno].numDistinctCols);

    for (int i = 0; i < peragg[aggno].numDistinctCols; i++) {
      LOG_INFO("sortColIdx[%d] : %d \n", i, peragg[aggno].sortColIdx[i]);
    }

  }  // end loop aggno

  /* Get Group by columns */
  std::vector<oid_t> groupby_col_ids;
  LOG_INFO("agg.numCols = %d", agg->numCols);
  for (int i = 0; i < agg->numCols; i++) {
    LOG_INFO("agg.grpColIdx[%d] = %d \n", i, agg->grpColIdx[i]);

    auto attrno = agg->grpColIdx[i];
    if (AttributeNumberIsValid(attrno) &&
        AttrNumberIsForUserDefinedAttr(attrno)) {
      groupby_col_ids.emplace_back(AttrNumberGetAttrOffset(attrno));
    }
  }

  /* Get output schema */
  std::unique_ptr<catalog::Schema> output_schema(
      SchemaTransformer::GetSchemaFromTupleDesc(tupleDesc));

  /* Map agg stragegy */
  LOG_INFO("aggstrategy : %s\n", (AGG_HASHED == aggstrategy)
                                     ? "HASH"
                                     : (AGG_SORTED ? "SORT" : "PLAIN"));

  PelotonAggType agg_type = AGGREGATE_TYPE_INVALID;

  switch (aggstrategy) {
    case AGG_SORTED:
      agg_type = AGGREGATE_TYPE_SORTED;
      break;
    case AGG_HASHED:
      agg_type = AGGREGATE_TYPE_HASH;
      break;
    case AGG_PLAIN:
      agg_type = AGGREGATE_TYPE_PLAIN;
      break;
  }

  std::vector<oid_t> column_ids;
  for (auto agg_term : unique_agg_terms) {
    if (agg_term.expression) {
      LOG_INFO("AGG TERM :: %s", agg_term.expression->Debug().c_str());
    }
    BuildColumnListFromExpr(column_ids, agg_term.expression);
  }

  auto retval = new planner::AggregatePlan(
      proj_info.release(), predicate.release(), std::move(unique_agg_terms),
      std::move(groupby_col_ids), output_schema.release(), agg_type);

  ((planner::AggregatePlan *)retval)->SetColumnIds(column_ids);

  // Find children
  auto lchild = TransformPlan(outerAbstractPlanState(plan_state));
  retval->AddChild(lchild);

  return retval;
}
Exemplo n.º 2
0
/*
 * get_args
 *   Retrieve arguments from FunctionCallInfo and validate them.  We assume
 *   that order of arguments is:
 *     1) schema name
 *     2) relation oid
 *     3) attribute name
 *     4) absolute path of source file, or 'stdin' (case insensitive)
 */
static void
get_args(FunctionCallInfo fcinfo, char **nspname, char **relname,
		char **attname, char **filename)
{
	Oid				nspid;
	Oid				relid;
	AttrNumber		attnum;
	HeapTuple		tp;
	Form_pg_class	reltup;
	char			relkind;

	*nspname = *relname = *attname = *filename = NULL;

	/*
	 * First of all, check whether combination of arguments is consistent.
	 *
	 * 1) relid and attname can't be used with schemaname.
	 * 2) relid is required when attname is given.
	 */
	if (!PG_ARGISNULL(0) && (!PG_ARGISNULL(1) || !PG_ARGISNULL(2)))
		elog(ERROR, "relid and attnum can not be used with schemaname");
	else if (PG_ARGISNULL(1) && !PG_ARGISNULL(2))
		elog(ERROR, "relation is required");

	/* filepath validation */
	if (!PG_ARGISNULL(3))
	{
		*filename = get_text_arg(fcinfo, 3, false);

		/*
		 * If given filepath is "stdin", clear filename to tell caller to
		 * import from standard input.  Note that we accept only absolute path
		 * for security reason.
		 */
		if (pg_strcasecmp(*filename, "stdin") == 0)
			*filename = NULL;
		else if (!is_absolute_path(*filename))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_NAME),
					 errmsg("relative path not allowed for dbms_stats_export"
							" to file")));
	}

	/* schemaname validation */
	if (!PG_ARGISNULL(0))
	{
		*nspname = get_text_arg(fcinfo, 0, true);

		/* check that a schema with given name exists */
		get_namespace_oid(*nspname, false);

		/* check that given schema is not one of system schemas */
		if (dbms_stats_is_system_schema_internal(*nspname))
			elog(ERROR, "\"%s\" is a system catalog", *nspname);
	}

	/* table oid validation */
	if (!PG_ARGISNULL(1))
	{
		relid = PG_GETARG_OID(1);
		tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
		if (!HeapTupleIsValid(tp))
			elog(ERROR, "relid %d does not exist", relid);

		/* check that the target is an ordinary table or an index */
		reltup = (Form_pg_class) GETSTRUCT(tp);
		*relname = pstrdup(reltup->relname.data);
		relkind = reltup->relkind;
		nspid = reltup->relnamespace;
		ReleaseSysCache(tp);

		if (relkind != RELKIND_RELATION && relkind != RELKIND_INDEX
#if PG_VERSION_NUM >= 90200
			&& relkind != RELKIND_FOREIGN_TABLE
#endif
#if PG_VERSION_NUM >= 90300
			&& relkind != RELKIND_MATVIEW
#endif
		)
			elog(ERROR, "relkind of \"%s\" is \"%c\", can not import",
				get_rel_name(relid), relkind);

		/* check that the relation is not in one of system schemas */
		*nspname = get_namespace_name(nspid);
		if (dbms_stats_is_system_schema_internal(*nspname))
			elog(ERROR, "\"%s\" is a system catalog", *nspname);

		/* attribute name validation */
		if (!PG_ARGISNULL(2))
		{
			*attname = get_text_arg(fcinfo, 2, true);
			attnum = get_attnum(relid, *attname);
			if (!AttributeNumberIsValid(attnum))
				elog(ERROR, "column \"%s\" of \"%s.%s\" does not exist", *attname, *nspname, *relname);
		}
	}
}