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; }
/* * 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); } } }