/* * Create an instance of an aggregator for the specified aggregate * type, column type, and result type. The object is constructed in * memory from the provided memrory pool. */ AbstractAttributeAggregator *GetAttributeAggregatorInstance(ExpressionType agg_type) { AbstractAttributeAggregator *aggregator; switch (agg_type) { case ExpressionType::AGGREGATE_COUNT: aggregator = new CountAggregator(); break; case ExpressionType::AGGREGATE_COUNT_STAR: aggregator = new CountStarAggregator(); break; case ExpressionType::AGGREGATE_SUM: aggregator = new SumAggregator(); break; case ExpressionType::AGGREGATE_AVG: aggregator = new AvgAggregator(false); break; case ExpressionType::AGGREGATE_MIN: aggregator = new MinAggregator(); break; case ExpressionType::AGGREGATE_MAX: aggregator = new MaxAggregator(); break; default: { std::string message = "Unknown aggregate type " + ExpressionTypeToString(agg_type); throw UnknownTypeException(static_cast<int>(agg_type), message); } } return aggregator; }
AbstractExpression *GetMoreSpecialized(ExpressionType c, L *l, R *r) { assert(l); assert(r); switch (c) { case (EXPRESSION_TYPE_COMPARE_EQUAL): return new InlinedComparisonExpression<CmpEq, L, R>(c, l, r); case (EXPRESSION_TYPE_COMPARE_NOTEQUAL): return new InlinedComparisonExpression<CmpNe, L, R>(c, l, r); case (EXPRESSION_TYPE_COMPARE_LESSTHAN): return new InlinedComparisonExpression<CmpLt, L, R>(c, l, r); case (EXPRESSION_TYPE_COMPARE_GREATERTHAN): return new InlinedComparisonExpression<CmpGt, L, R>(c, l, r); case (EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO): return new InlinedComparisonExpression<CmpLte, L, R>(c, l, r); case (EXPRESSION_TYPE_COMPARE_GREATERTHANOREQUALTO): return new InlinedComparisonExpression<CmpGte, L, R>(c, l, r); case (EXPRESSION_TYPE_COMPARE_LIKE): return new InlinedComparisonExpression<CmpLike, L, R>( c, l, r); // added by michael case (EXPRESSION_TYPE_COMPARE_IN): return new InlinedComparisonExpression<CmpIn, L, R>( c, l, r); // added by michael default: char message[256]; sprintf(message, "Invalid ExpressionType '%s' called for" " ComparisonExpression", ExpressionTypeToString(c).c_str()); throw ExpressionException(message); } }
void AbstractExpression::DeduceExpressionName() { // If alias exists, it will be used in TrafficCop if (!alias.empty()) return; for (auto &child : children_) child->DeduceExpressionName(); // Aggregate expression already has correct expr_name_ if (ExpressionUtil::IsAggregateExpression(exp_type_)) return; auto op_str = ExpressionTypeToString(exp_type_, true); auto children_size = children_.size(); if (exp_type_ == ExpressionType::FUNCTION) { auto expr = (FunctionExpression *)this; expr_name_ = expr->GetFuncName() + "("; for (size_t i = 0; i < children_size; i++) { if (i > 0) expr_name_.append(","); expr_name_.append(GetChild(i)->expr_name_); } expr_name_.append(")"); } else { PL_ASSERT(children_size <= 2); if (children_size == 2) { expr_name_ = GetChild(0)->expr_name_ + " " + op_str + " " + GetChild(1)->expr_name_; } else if (children_size == 1) { expr_name_ = op_str + " " + GetChild(0)->expr_name_; } } }
AbstractExpression *GetGeneral(ExpressionType c, AbstractExpression *l, AbstractExpression *r) { PL_ASSERT(l); PL_ASSERT(r); switch (c) { case (EXPRESSION_TYPE_COMPARE_EQUAL): return new ComparisonExpression<CmpEq>(c, l, r); case (EXPRESSION_TYPE_COMPARE_NOTEQUAL): return new ComparisonExpression<CmpNe>(c, l, r); case (EXPRESSION_TYPE_COMPARE_LESSTHAN): return new ComparisonExpression<CmpLt>(c, l, r); case (EXPRESSION_TYPE_COMPARE_GREATERTHAN): return new ComparisonExpression<CmpGt>(c, l, r); case (EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO): return new ComparisonExpression<CmpLte>(c, l, r); case (EXPRESSION_TYPE_COMPARE_GREATERTHANOREQUALTO): return new ComparisonExpression<CmpGte>(c, l, r); case (EXPRESSION_TYPE_COMPARE_LIKE): return new ComparisonExpression<CmpLike>(c, l, r); case (EXPRESSION_TYPE_COMPARE_NOTLIKE): return new ComparisonExpression<CmpNotLike>(c, l, r); case (EXPRESSION_TYPE_COMPARE_IN): return new ComparisonExpression<CmpIn>(c, l, r); default: char message[256]; snprintf(message, 256, "Invalid ExpressionType '%s' called" " for ComparisonExpression", ExpressionTypeToString(c).c_str()); throw Exception(message); } }
std::string AbstractExpression::Debug() const { if (this == nullptr) return ""; std::ostringstream buffer; buffer << "Expression[" << ExpressionTypeToString(GetExpressionType()) << ", " << GetExpressionType() << "]"; return (buffer.str()); }
SeqScanPlan::SeqScanPlan(parser::SelectStatement *select_node) { LOG_DEBUG("Creating a Sequential Scan Plan"); auto target_table = static_cast<storage::DataTable *>( catalog::Catalog::GetInstance()->GetTableWithName( select_node->from_table->GetDatabaseName(), select_node->from_table->GetTableName())); SetTargetTable(target_table); ColumnIds().clear(); // Check if there is an aggregate function in query bool function_found = false; for (auto elem : *select_node->select_list) { if (elem->GetExpressionType() == EXPRESSION_TYPE_FUNCTION_REF) { function_found = true; break; } } // Pass all columns // TODO: This isn't efficient. Needs to be fixed if (function_found) { for (auto column : GetTable()->GetSchema()->GetColumns()) { oid_t col_id = SeqScanPlan::GetColumnID(column.column_name); SetColumnId(col_id); } } // Pass columns in select_list else { if (select_node->select_list->at(0)->GetExpressionType() != EXPRESSION_TYPE_STAR) { for (auto col : *select_node->select_list) { LOG_TRACE("ExpressionType: %s", ExpressionTypeToString(col->GetExpressionType()).c_str()); auto col_name = col->GetName(); oid_t col_id = SeqScanPlan::GetColumnID(std::string(col_name)); SetColumnId(col_id); } } else { auto allColumns = GetTable()->GetSchema()->GetColumns(); for (uint i = 0; i < allColumns.size(); i++) SetColumnId(i); } } // Check for "For Update" flag if(select_node->is_for_update == true){ SetForUpdateFlag(true); } // Keep a copy of the where clause to be binded to values if (select_node->where_clause != NULL) { auto predicate = select_node->where_clause->Copy(); // Replace COLUMN_REF expressions with TupleValue expressions expression::ExpressionUtil::ReplaceColumnExpressions(GetTable()->GetSchema(), predicate); predicate_with_params_ = std::unique_ptr<expression::AbstractExpression>(predicate->Copy()); SetPredicate(predicate); } }
const std::string ComparisonExpression::GetInfo(int num_indent) const { std::ostringstream os; os << StringUtil::Indent(num_indent) << "Expression ::\n" << StringUtil::Indent(num_indent + 1) << "expression type = Comparison,\n" << StringUtil::Indent(num_indent + 1) << "comparison type = " << ExpressionTypeToString(exp_type_) << "\n"; for (const auto &child : children_) { os << child.get()->GetInfo(num_indent + 2); } return os.str(); }
// Produce the value that is the result of codegening the expression codegen::Value ConjunctionTranslator::DeriveValue(CodeGen &codegen, RowBatch::Row &row) const { const auto &conjunction = GetExpressionAs<expression::ConjunctionExpression>(); codegen::Value left = row.DeriveValue(codegen, *conjunction.GetChild(0)); codegen::Value right = row.DeriveValue(codegen, *conjunction.GetChild(1)); switch (conjunction.GetExpressionType()) { case ExpressionType::CONJUNCTION_AND: return left.LogicalAnd(codegen, right); case ExpressionType::CONJUNCTION_OR: return left.LogicalOr(codegen, right); default: throw Exception{"Received a non-conjunction expression type: " + ExpressionTypeToString(conjunction.GetExpressionType())}; } }
//===--------------------------------------------------------------------===// // Plain Aggregator //===--------------------------------------------------------------------===// PlainAggregator::PlainAggregator(const planner::AggregatePlan *node, storage::DataTable *output_table, executor::ExecutorContext *econtext) : AbstractAggregator(node, output_table, econtext) { // allocate aggregators aggregates = new Agg *[node->GetUniqueAggTerms().size()](); // initialize aggregators for (oid_t aggno = 0; aggno < node->GetUniqueAggTerms().size(); aggno++) { LOG_TRACE("Aggregate term type: %s", ExpressionTypeToString( node->GetUniqueAggTerms()[aggno].aggtype).c_str()); aggregates[aggno] = GetAggInstance(node->GetUniqueAggTerms()[aggno].aggtype); bool distinct = node->GetUniqueAggTerms()[aggno].distinct; aggregates[aggno]->SetDistinct(distinct); } }
TEST_F(BooleanValueTests, ComparisonTest) { std::vector<ExpressionType> compares = { ExpressionType::COMPARE_EQUAL, ExpressionType::COMPARE_NOTEQUAL, ExpressionType::COMPARE_LESSTHAN, ExpressionType::COMPARE_LESSTHANOREQUALTO, ExpressionType::COMPARE_GREATERTHAN, ExpressionType::COMPARE_GREATERTHANOREQUALTO}; int values[] = {true, false, type::PELOTON_BOOLEAN_NULL}; CmpBool result; type::Value val0; type::Value val1; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { bool expected_null = false; // VALUE #0 if (values[i] == type::PELOTON_BOOLEAN_NULL) { val0 = type::ValueFactory::GetNullValueByType(type::TypeId::BOOLEAN); expected_null = true; } else { val0 = type::ValueFactory::GetBooleanValue(static_cast<bool>(values[i])); } // VALUE #1 if (values[j] == type::PELOTON_BOOLEAN_NULL) { val1 = type::ValueFactory::GetNullValueByType(type::TypeId::BOOLEAN); expected_null = true; } else { val1 = type::ValueFactory::GetBooleanValue(static_cast<bool>(values[j])); } for (auto etype : compares) { bool expected; switch (etype) { case ExpressionType::COMPARE_EQUAL: expected = values[i] == values[j]; result = val0.CompareEquals(val1); break; case ExpressionType::COMPARE_NOTEQUAL: expected = values[i] != values[j]; result = val0.CompareNotEquals(val1); break; case ExpressionType::COMPARE_LESSTHAN: expected = values[i] < values[j]; result = val0.CompareLessThan(val1); break; case ExpressionType::COMPARE_LESSTHANOREQUALTO: expected = values[i] <= values[j]; result = val0.CompareLessThanEquals(val1); break; case ExpressionType::COMPARE_GREATERTHAN: expected = values[i] > values[j]; result = val0.CompareGreaterThan(val1); break; case ExpressionType::COMPARE_GREATERTHANOREQUALTO: expected = values[i] >= values[j]; result = val0.CompareGreaterThanEquals(val1); break; default: throw Exception("Unexpected comparison"); } // SWITCH LOG_TRACE("%s %s %s => %d | %d\n", val0.ToString().c_str(), ExpressionTypeToString(etype).c_str(), val1.ToString().c_str(), static_cast<int>(expected), static_cast<int>(result)); if (expected_null) expected = false; EXPECT_EQ(expected, result == CmpBool::CmpTrue); EXPECT_EQ(!expected, result == CmpBool::CmpFalse); EXPECT_EQ(expected_null, result == CmpBool::NULL_); } } } }
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; }
TEST_F(TimestampValueTests, ComparisonTest) { std::vector<ExpressionType> compares = { ExpressionType::COMPARE_EQUAL, ExpressionType::COMPARE_NOTEQUAL, ExpressionType::COMPARE_LESSTHAN, ExpressionType::COMPARE_LESSTHANOREQUALTO, ExpressionType::COMPARE_GREATERTHAN, ExpressionType::COMPARE_GREATERTHANOREQUALTO}; uint64_t values[] = {1000000000, 2000000000, type::PELOTON_TIMESTAMP_NULL}; type::CmpBool result; type::Value val0; type::Value val1; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { bool expected_null = false; // VALUE #0 if (values[i] == type::PELOTON_TIMESTAMP_NULL) { val0 = type::ValueFactory::GetNullValueByType(type::TypeId::TIMESTAMP); expected_null = true; } else { val0 = type::ValueFactory::GetTimestampValue( static_cast<uint64_t>(values[i])); } // VALUE #1 if (values[j] == type::PELOTON_TIMESTAMP_NULL) { val1 = type::ValueFactory::GetNullValueByType(type::TypeId::TIMESTAMP); expected_null = true; } else { val1 = type::ValueFactory::GetTimestampValue( static_cast<uint64_t>(values[j])); } bool temp = expected_null; for (auto etype : compares) { bool expected; expected_null = temp; switch (etype) { case ExpressionType::COMPARE_EQUAL: expected = values[i] == values[j]; result = val0.CompareEquals(val1); break; case ExpressionType::COMPARE_NOTEQUAL: expected = values[i] != values[j]; result = val0.CompareNotEquals(val1); if (!val1.IsNull() && expected_null) { expected_null = false; } break; case ExpressionType::COMPARE_LESSTHAN: expected = values[i] < values[j]; result = val0.CompareLessThan(val1); break; case ExpressionType::COMPARE_LESSTHANOREQUALTO: expected = values[i] <= values[j]; result = val0.CompareLessThanEquals(val1); break; case ExpressionType::COMPARE_GREATERTHAN: expected = values[i] > values[j]; result = val0.CompareGreaterThan(val1); break; case ExpressionType::COMPARE_GREATERTHANOREQUALTO: expected = values[i] >= values[j]; result = val0.CompareGreaterThanEquals(val1); break; default: throw Exception("Unexpected comparison"); } // SWITCH LOG_TRACE("%s %s %s => %d | %d\n", val0.ToString().c_str(), ExpressionTypeToString(etype).c_str(), val1.ToString().c_str(), expected, result); if (expected_null) { EXPECT_EQ(expected_null, result == type::CMP_NULL); } else { EXPECT_EQ(expected, result == type::CMP_TRUE); EXPECT_EQ(!expected, result == type::CMP_FALSE); } } } } }