text: /*
   * Copyright 2018-2019 Redis Labs Ltd. and Contributors
   *
   * This file is available under the Redis Labs Source Available License Agreement
   */
  
  #include "relocate_op.h"
  
  /* Locate the closest projection or aggregation op
   * in the execution chain of the given operation. */
  static OpBase *_locateProjection(OpBase *root) {
  	if(!root) return NULL;
  
  	if(root->type == OPType_PROJECT || root->type == OPType_AGGREGATE) {
  		return root;
  	}
  
  	for(int i = 0; i < root->childCount; i++) {
  		OpBase *op = _locateProjection(root->children[i]);
  		if(op) return op;
  	}
  
  	return NULL;
  }
  
  /* Migrate the given operation directly above the project/aggregate operation. */
  void _relocateOp(ExecutionPlan *plan, OPType type) {
  	OpBase *op = ExecutionPlan_LocateOp(plan->root, type);
  	if(!op) return;
  	assert(op->childCount == 1);
  
  	// Find the first projection or aggregation in the operation's chain
  	OpBase *projection_op = _locateProjection(op->children[0]);
  	assert(projection_op);
  
  	// Remove op from its current position.
  	ExecutionPlan_RemoveOp(plan, op);
  	// Push op right above projection/aggregation
  	ExecutionPlan_PushBelow(projection_op, op);
  }
  
  void relocateOperations(ExecutionPlan *plan) {
  	assert(plan && plan->root);
  	_relocateOp(plan, OPType_LIMIT);
  	_relocateOp(plan, OPType_SKIP);
  	_relocateOp(plan, OPType_SORT);
  	_relocateOp(plan, OPType_DISTINCT);
  }
  