#include "binder/expression/property_expression.h"
#include "binder/expression/scalar_function_expression.h"
#include "catalog/catalog.h"
#include "catalog/catalog_entry/rel_group_catalog_entry.h"
#include "function/schema/vector_node_rel_functions.h"
#include "processor/operator/arrow_result_collector.h"
#include "processor/physical_plan_util.h"
#include "processor/plan_mapper.h"
#include "storage/storage_manager.h"
#include "storage/table/node_table.h"
#include "transaction/transaction.h"
using namespace lbug::common;
namespace lbug {
namespace processor {
static bool isProjectedRowIDExpr(const binder::Expression& expr) {
if (expr.expressionType != ExpressionType::FUNCTION) {
return false;
}
const auto& scalarFunc = expr.constCast<binder::ScalarFunctionExpression>();
if (scalarFunc.getFunction().name != function::OffsetFunction::name ||
scalarFunc.getNumChildren() != 1) {
return false;
}
const auto child = scalarFunc.getChild(0);
if (child->expressionType != ExpressionType::PROPERTY) {
return false;
}
const auto& property = child->constCast<binder::PropertyExpression>();
return property.isInternalID();
}
static CSRTrackingInfo getCSRTrackingInfo(const binder::expression_vector& expressions) {
CSRTrackingInfo info;
std::vector<idx_t> rowIDExprPositions;
for (auto i = 0u; i < expressions.size(); ++i) {
if (isProjectedRowIDExpr(*expressions[i])) {
rowIDExprPositions.push_back(i);
}
}
if (rowIDExprPositions.size() == 2) {
info.srcRowIDColIdx = rowIDExprPositions[0];
info.dstRowIDColIdx = rowIDExprPositions[1];
} else if (rowIDExprPositions.size() == 3) {
info.srcRowIDColIdx = rowIDExprPositions[0];
info.relRowIDColIdx = rowIDExprPositions[1];
info.dstRowIDColIdx = rowIDExprPositions[2];
}
return info;
}
static common::table_id_t getRowIDExprTableID(const binder::Expression& expr) {
const auto& scalarFunc = expr.constCast<binder::ScalarFunctionExpression>();
const auto& propExpr = scalarFunc.getChild(0)->constCast<binder::PropertyExpression>();
return propExpr.getSingleTableID();
}
static const catalog::RelGroupCatalogEntry* getScannedRelGroupEntry(const CSRTrackingInfo& info,
const binder::expression_vector& expressions, const transaction::Transaction* trx,
main::ClientContext* clientContext) {
auto catalog = catalog::Catalog::Get(*clientContext);
if (info.hasRelRowID()) {
const auto relGroupID = getRowIDExprTableID(*expressions[info.relRowIDColIdx]);
return catalog->getTableCatalogEntry(trx, relGroupID)
->ptrCast<catalog::RelGroupCatalogEntry>();
}
const auto srcTableID = getRowIDExprTableID(*expressions[info.srcRowIDColIdx]);
const auto dstTableID = getRowIDExprTableID(*expressions[info.dstRowIDColIdx]);
for (auto* relGroup : catalog->getRelGroupEntries(trx)) {
for (const auto& relInfo : relGroup->getRelEntryInfos()) {
if ((relInfo.nodePair.srcTableID == srcTableID &&
relInfo.nodePair.dstTableID == dstTableID) ||
(relInfo.nodePair.srcTableID == dstTableID &&
relInfo.nodePair.dstTableID == srcTableID)) {
return relGroup;
}
}
}
return nullptr;
}
std::unique_ptr<PhysicalOperator> PlanMapper::createArrowResultCollector(
ArrowResultConfig arrowConfig, const binder::expression_vector& expressions,
planner::Schema* schema, std::unique_ptr<PhysicalOperator> prevOperator,
OrderPreservationType orderPreservation) {
std::vector<DataPos> columnDataPos;
std::vector<LogicalType> columnTypes;
for (auto& expr : expressions) {
columnDataPos.push_back(getDataPos(*expr, *schema));
columnTypes.push_back(expr->getDataType().copy());
}
auto sharedState = std::make_shared<ArrowResultCollectorSharedState>();
sharedState->requireDeterministicOrder =
(orderPreservation == OrderPreservationType::FIXED_ORDER);
auto csrTrackingInfo = getCSRTrackingInfo(expressions);
if (csrTrackingInfo.enabled()) {
const auto tableID = getRowIDExprTableID(*expressions[csrTrackingInfo.srcRowIDColIdx]);
auto trx = transaction::Transaction::Get(*clientContext);
auto table = storage::StorageManager::Get(*clientContext)->getTable(tableID);
auto nodeTable = table->ptrCast<storage::NodeTable>();
csrTrackingInfo.numSourceRows = static_cast<int64_t>(nodeTable->getNumTotalRows(trx));
const auto* relGroupEntry =
getScannedRelGroupEntry(csrTrackingInfo, expressions, trx, clientContext);
if (relGroupEntry != nullptr && relGroupEntry->isCsrSortedByDest() &&
!relGroupEntry->getRelEntryInfos().empty()) {
const auto relOid = relGroupEntry->getRelEntryInfos()[0].oid;
auto* relTable = storage::StorageManager::Get(*clientContext)->getTable(relOid);
if (relTable != nullptr &&
relGroupEntry->getCsrChangeEpoch() == relTable->getChangeEpoch()) {
csrTrackingInfo.sortedByDest = true;
}
}
}
auto opInfo = ArrowResultCollectorInfo(arrowConfig.chunkSize, columnDataPos,
std::move(columnTypes), csrTrackingInfo, orderPreservation);
auto printInfo = OPPrintInfo::EmptyInfo();
if (csrTrackingInfo.enabled() &&
(expressions.size() == 2 || (expressions.size() == 3 && csrTrackingInfo.hasRelRowID()))) {
auto op = std::make_unique<DirectArrowResultCollector>(sharedState, std::move(opInfo),
std::move(prevOperator), getOperatorID(), std::move(printInfo));
op->setDescriptor(std::make_unique<ResultSetDescriptor>(schema));
return op;
}
auto op = std::make_unique<ArrowResultCollector>(sharedState, std::move(opInfo),
std::move(prevOperator), getOperatorID(), std::move(printInfo));
op->setDescriptor(std::make_unique<ResultSetDescriptor>(schema));
return op;
}
} }