//---------------------------------------------------------------------------
// Greenplum Database
// Copyright (c) 2024 VMware, Inc. or its affiliates. All Rights Reserved.
//
// @filename:
// CJoinHint.h
//
// @doc:
// CJoinHint represents an ORCA optimizer hint that specifies an order to
// join on a set of table(s) and/or alias(es). There are 2 syntaxes:
// direction and direction-less.
//
// Example (direction):
// /*+ Leading((t3 (t2 t1))) */ SELECT * FROM t1, t2, t3;
//
// Hint specifies that t2 and t1 are joined first where t2 is the outer
// side and t1 is inner side. Then the result is joined with t3 where t3
// is on the outer side.
//
// DXL format:
//
//
// Example (direction-less):
// /*+ Leading(t3 t2 t1) */ SELECT * FROM t1, t2, t3;
//
// Hint specifies that t3 and t2 are joined first and may be on either of
// the join. Then the result is joined with t1 where t1 is on either side
// of the join.
//
// DXL format:
//
//---------------------------------------------------------------------------
#ifndef GPOS_CJoinHint_H
#define GPOS_CJoinHint_H
#include "gpos/base.h"
#include "gpos/common/CDynamicPtrArray.h"
#include "gpos/common/CRefCount.h"
#include "gpopt/exception.h"
#include "gpopt/hints/IHint.h"
#include "gpopt/operators/CExpression.h"
#include "gpopt/operators/COperator.h"
#include "naucrates/dxl/xml/CXMLSerializer.h"
namespace gpopt
{
class CJoinHint : public IHint, public DbgPrintMixin
{
public:
// JoinNode represent join order over a set of relations
//
// Let's say the hint is Leading(t3 (t2 t1)), then the JoinNode would be:
//
// [JoinNode]
// outer|inner
// / \ .
// / \ .
// [JoinNode] \ .
// t3 [JoinNode] .
// outer|inner .
// / \ .
// / \ .
// [JoinNode] [JoinNode]
// t2 t1
class JoinNode : public CRefCount, public DbgPrintMixin
{
private:
// alias or table name. null if non-leaf node.
CWStringConst *m_name{nullptr};
// outer join pair. null if leaf node.
JoinNode *m_outer{nullptr};
// inner join pair. null if leaf node.
JoinNode *m_inner{nullptr};
// directed "true" means that the inner/outer sides cannot be swapped.
bool m_is_directed{false};
public:
// ctor for leaf nodes
JoinNode(CWStringConst *name) : m_name(name)
{
}
// ctor for branch nodes
JoinNode(JoinNode *outer, JoinNode *inner, bool is_directed)
: m_outer(outer), m_inner(inner), m_is_directed(is_directed)
{
}
~JoinNode() override
{
GPOS_DELETE(m_name);
CRefCount::SafeRelease(m_outer);
CRefCount::SafeRelease(m_inner);
}
CWStringConst *
GetName() const
{
return m_name;
}
JoinNode *
GetOuter() const
{
return m_outer;
}
JoinNode *
GetInner() const
{
return m_inner;
}
bool
IsDirected() const
{
return m_is_directed;
}
IOstream &OsPrint(IOstream &os) const;
};
private:
CMemoryPool *m_mp;
// stores specified join order
JoinNode *m_join_node{nullptr};
public:
CJoinHint(CMemoryPool *mp, JoinNode *join_pair);
~CJoinHint() override
{
m_join_node->Release();
}
const CJoinHint::JoinNode *
GetJoinNode() const
{
return m_join_node;
}
IOstream &OsPrint(IOstream &os) const;
void Serialize(CXMLSerializer *xml_serializer);
};
using JoinHintList = CDynamicPtrArray;
} // namespace gpopt
#endif // !GPOS_CJoinHint_H
// EOF