blob: c48a641db95a2cb9c81977539e96f796465bf7f6 [file] [log] [blame]
// **********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
// **********************************************************************
// ***********************************************************************
//
// File: QRJoinGraph.h
// Description:
//
//
//
//
// Created: 12/11/07
// ***********************************************************************
// _MEMSHAREDPTR;_MEMCHECK
#include "NABasicObject.h"
#include "NAString.h"
#include "Collections.h"
#include "Int64.h"
#include "QRSharedPtr.h"
#include "QRDescriptor.h"
class JoinGraphTable;
class JoinGraphHalfPredicate;
class JoinGraphEqualitySet;
class QRJoinGraph;
class QRJoinSubGraph;
class QRJoinSubGraphMap;
#ifdef _MEMSHAREDPTR
typedef QRIntrusiveSharedPtr<JoinGraphTable> JoinGraphTablePtr;
typedef QRIntrusiveSharedPtr<JoinGraphHalfPredicate> JoinGraphHalfPredicatePtr;
typedef QRIntrusiveSharedPtr<JoinGraphEqualitySet> JoinGraphEqualitySetPtr;
typedef QRIntrusiveSharedPtr<QRJoinGraph> QRJoinGraphPtr;
typedef QRIntrusiveSharedPtr<QRJoinSubGraph> QRJoinSubGraphPtr;
typedef QRIntrusiveSharedPtr<QRJoinSubGraphMap> QRJoinSubGraphMapPtr;
#else
typedef JoinGraphTable* JoinGraphTablePtr;
typedef JoinGraphHalfPredicate* JoinGraphHalfPredicatePtr;
typedef JoinGraphEqualitySet* JoinGraphEqualitySetPtr;
typedef QRJoinGraph* QRJoinGraphPtr;
typedef QRJoinSubGraph* QRJoinSubGraphPtr;
typedef QRJoinSubGraphMap* QRJoinSubGraphMapPtr;
#endif
typedef NAPtrList<JoinGraphHalfPredicatePtr> HalfPredicateList;
typedef NAPtrList<JoinGraphEqualitySetPtr> EqualitySetList;
typedef NAPtrList<JoinGraphTablePtr> JoinGraphTableList;
typedef NAPtrArray<JoinGraphTablePtr> JoinGraphTableArray;
typedef NASubArray<JoinGraphTablePtr> JoinGraphTableSubArray;
typedef NAPtrList<QRJoinSubGraphPtr> SubGraphList;
typedef NAPtrList<QRJoinSubGraphMapPtr> SubGraphMapList;
typedef SharedPtrValueHash<const NAString, JoinGraphTable> JoinGraphTableHash;
typedef SharedPtrValueHashIterator<const NAString, JoinGraphTable> JoinGraphTableHashIterator;
typedef SharedPtrValueHash<const NAString, QRJoinSubGraph> SubGraphHash;
typedef SharedPtrValueHashIterator<const NAString, QRJoinSubGraph> SubGraphHashIterator;
#ifndef _QRJOINGRAPH_H_
#define _QRJOINGRAPH_H_
enum OperationType { OP_INSERT = 0, OP_SEARCH, OP_INSERT_TOP };
#include "QmsMVDetails.h"
#include "QmsMVCandidate.h"
#include "QmsSelfJoinHandler.h"
/**
* A JoinGraphTable is a node in the join graph.
* It holds the table name, its descriptor ID, and pointers to predicates.
* The ordinal number of a table is its index into the QRJoinGraph table array.
* The temp number is used when building the MVMemo hash key.
*
* @see QRJoinGraph
* @see JoinGraphHalfPredicate
* @see JoinGraphEqualitySet
* @see QRJoinSubGraph
*****************************************************************************
*/
class JoinGraphTable : public NAIntrusiveSharedPtrObject
{
public:
/**
* Public constructor.
* @param num The ordinal number - the index of this table into the QRJoinGraph table array.
* @param tableElement Table element from the descriptor.
* @param heap Heap from which to allocate internal data members.
*/
JoinGraphTable(CollIndex num,
const QRTablePtr tableElement,
NABoolean isHub,
const BaseTableDetailsPtr baseTable,
ADD_MEMCHECK_ARGS_DECL(CollHeap* heap))
: NAIntrusiveSharedPtrObject(ADD_MEMCHECK_ARGS_PASS(heap))
,ordinalNumber_(num)
,tempNumber_(-1)
,keyColumns_(0)
,reducedConnections_(0)
,tableElement_(tableElement)
,isHub_(isHub)
,baseTable_(baseTable)
,predList_(heap)
,name_(tableElement->getTableName())
,isSelfJoinTable_(FALSE)
{}
virtual ~JoinGraphTable() {}
NABoolean operator==(const JoinGraphTable& other)
{
return ordinalNumber_ == other.ordinalNumber_;
}
/** Get the ordinal number - the index into the QRJoinGraph table array. */
CollIndex getOrdinalNumber() const { return ordinalNumber_; }
/** Get the temp number - used when building the MVMemo hash key. */
Int32 getTempNumber() const { return tempNumber_; }
/** Get the table name. */
const NAString& getName() const { return tableElement_->getTableName(); }
/** Get the table element ID from the MV/query descriptor. */
const NAString& getID() const { return tableElement_->getID(); }
/** Get the table element from the descriptor. */
const QRTablePtr getTableElement() const { return tableElement_; }
const BaseTableDetailsPtr getBaseTable() const { return baseTable_; }
NABoolean isHub() const { return isHub_; };
/** Get the list of equality sets involving this table. */
const EqualitySetList& getEqualitySets() { return predList_; }
/** Set the table's ordinal number. Used after the QRJoinGraph table array is re-ordered. */
void setOrdinalNumber(CollIndex ix) { ordinalNumber_ = ix; }
/** Set the table's temp number. Used when marking the table during generation of a sub-graph.*/
void setTempNumber(Int32 ix) { tempNumber_ = ix; }
/** Add an equality set. */
void addEqualitySet(JoinGraphEqualitySetPtr pred)
{
predList_.insert(pred);
}
/** Remove an equality set. */
void removeEqualitySet(JoinGraphEqualitySetPtr pred)
{
predList_.remove(pred);
}
/** Clear the table's equality sets list. */
void clearEqualitySets() { predList_.clear(); }
/** Add a line with this table's information to the graphical join graph in the output parameter string. */
void dumpGraph(NAString& to);
/** Is this table directly connected to the sub-graph? */
NABoolean isConnectedTo(const QRJoinSubGraphPtr subGraph) const;
/** Find an equality set from the ones this table is connected to, that match otherHalfPred, which is from a different join graph. */
JoinGraphEqualitySetPtr getEqSetUsing(JoinGraphHalfPredicatePtr otherHalfPred);
/** Check if predicates on this table are on its key columns. */
NABoolean checkPredsOnKey(CollHeap* heap);
void reduceConnection()
{
reducedConnections_++;
}
NABoolean isOnTheEdge();
void setSelfJoinTable()
{
isSelfJoinTable_ = TRUE;
}
NABoolean isSelfJoinTable()
{
return isSelfJoinTable_;
}
void getAndReducePredicateColumnsPointingToMe(ElementPtrList& pointingCols);
Int32 getDegree();
private:
// Copy construction/assignment not defined.
JoinGraphTable(const JoinGraphTable&);
JoinGraphTable& operator=(const JoinGraphTable&);
private:
/** Index into the QRJoinGraph table array. */
CollIndex ordinalNumber_;
/** Used when building the MVMemo hash key. */
Int32 tempNumber_;
/** Used for indirect GroupBy detection */
CollIndex keyColumns_;
CollIndex reducedConnections_;
/** 3-part name of the table. */
const NAString& name_;
/** Pointer to table element from the descriptor. */
const QRTablePtr tableElement_;
/** Is this a hub table? */
NABoolean isHub_;
/** List of equi-join predicates involving this table. */
EqualitySetList predList_;
/** A pointer to this table's BaseTableDetails object. */
const BaseTableDetailsPtr baseTable_;
/** Does the join graph contain more than one instance of this table? */
NABoolean isSelfJoinTable_;
}; // class JoinGraphTable
/**
* A "Half Predicate" is an expression that can be found in either side
* of the equal sign in an equi-join predicate. It holds an expression
* text and a pointer to a table that includes all the columns used by
* the expression. The expression is typically a name of a single column,
* but if it is more complex, all the columns it uses must be of the same
* table.
*
* @see QRJoinGraph
* @see JoinGraphTable
* @see JoinGraphEqualitySet
* @see QRJoinSubGraph
*****************************************************************************
*/
class JoinGraphHalfPredicate : public NAIntrusiveSharedPtrObject
{
public:
/**
* Public constructor.
* @param tablePtr The table this half-pred is pointing to.
* @param expr The half-pred expression (or column name).
* @param id The element ID from the MV/query descriptor.
* @param heap Heap from which to allocate internal data members.
*/
JoinGraphHalfPredicate(const JoinGraphTablePtr tablePtr,
const QRElementPtr elementPtr,
const NAString& expr,
ADD_MEMCHECK_ARGS_DECL(CollHeap* heap))
: NAIntrusiveSharedPtrObject(ADD_MEMCHECK_ARGS_PASS(heap))
,tablePtr_(tablePtr)
,elementPtr_(elementPtr)
,expr_(expr, heap)
{}
/** Get the table this half-pred is pointing to. */
const JoinGraphTablePtr getTable() const { return tablePtr_; }
/** Get the half-pred expression. */
const NAString& getExpr() const { return expr_; }
/** Get the descriptor ID. */
const NAString& getID() const { return elementPtr_->getID(); }
/** Get the descriptor element */
const QRElementPtr getElementPtr() const { return elementPtr_; }
/**
* Match this halfPred to other, which is from a different join graph.
* Match only the expression text, not the destination table.
* @param other The halfPred from the other join graph.
* @return TRUE if matching, FALSE otherwise.
*/
NABoolean match(JoinGraphHalfPredicatePtr other) const
{
return getExpr() == other->getExpr();
}
private:
// Copy construction/assignment not defined.
JoinGraphHalfPredicate(const JoinGraphHalfPredicate&);
JoinGraphHalfPredicate& operator=(const JoinGraphHalfPredicate&);
private:
const JoinGraphTablePtr tablePtr_;
const NAString expr_;
const QRElementPtr elementPtr_;
}; // class JoinGraphHalfPredicate
/**
* An equality set is a list of "half predicates", that are all declared
* as equal by the query's equi-join predicates.
*
* @see QRJoinGraph
* @see JoinGraphTable
* @see JoinGraphHalfPredicate
* @see QRJoinSubGraph
*****************************************************************************
*/
class JoinGraphEqualitySet : public NAIntrusiveSharedPtrObject
{
public:
/**
* Public constructor.
* @param id The equi-join predicate element ID from the MV/query descriptor.
* @param heap Heap from which to allocate internal data members.
*/
JoinGraphEqualitySet(const NAString& id,
ADD_MEMCHECK_ARGS_DECL(CollHeap* heap))
: NAIntrusiveSharedPtrObject(ADD_MEMCHECK_ARGS_PASS(heap))
,halfPreds_(heap)
,descriptorID_(id, heap)
,maxExprSize_(0)
// ,tempNumber_(-1)
,isOnKey_(FALSE)
,keyDirection_(0)
{}
virtual ~JoinGraphEqualitySet()
{
// Delete all the half preds.
JoinGraphHalfPredicatePtr pred;
while (halfPreds_.entries() > 0)
{
CollIndex last = halfPreds_.entries()-1;
pred = halfPreds_[last];
halfPreds_.removeAt(last);
deletePtr(pred);
pred = NULL;
}
}
/** Get the descriptor ID. */
const NAString& getID() { return descriptorID_; }
/** Get the list of half-preds in this equality set. */
HalfPredicateList& getHalfPredicates() { return halfPreds_; }
// Temp numbers are not used for now, because equality set lines
// in the MVMemo hash key are not numbered. This may change...
// int getTempNumber() { return tempNumber_; }
// void setTempNumber(int ix) { tempNumber_ = ix; }
/** Add a half-pred to the equality set. */
void addHalfPredicate(JoinGraphHalfPredicatePtr pred)
{
halfPreds_.insert(pred);
// Maintain the size of the longest column/expression.
if (pred->getExpr().length() > maxExprSize_)
maxExprSize_ = pred->getExpr().length();
}
/**
* Union this and other equality sets by adding all the half preds
* from other into this, and remove them from other.
*/
void addHalfPredicatesFrom(JoinGraphEqualitySetPtr other);
/**
* Is this equality set part of the current subgraph?
* @return TRUE if this subgraph has at least two half-predicates
* that are part of the subgraph, that is, have a tempNumber other
* than -1.
*/
NABoolean isInCurrentSubGraph();
/**
* Generate the MVMemo hash key line for this equality set:
* \par
* 1. Collect the list of half predicates on participating tables.\par
* 2. Format them as <table-temp-number>.<column-name/expression> \par
* 3. Sort them. \par
* 4. Generate a single line in the format: <tt>{1.CUSTOMER_ID,2.ORDERED_BY}</tt> \par
* The result is returned in an NAString object allocated off the heap.
* @return the formatted hash key line.
*/
NAString* getHashKeyLine(CollHeap* heap);
/**
* Is this equality set directly connected to the sub-graph.
*/
NABoolean isConnectedTo(const QRJoinSubGraphPtr subGraph) const;
/**
* Find the halfPred pointing to sourceTable (must be from the same join graph).
*/
const JoinGraphHalfPredicatePtr findHalfPredTo(const JoinGraphTablePtr sourceTable) const;
/**
* Sets this equality set as a join predicate on a key column of the target table.
* @param targetTable
*/
void setOnKeyTo(const JoinGraphTablePtr targetTable);
/**
* Is this equality set a joinpredicate on the target table's key column?
* @param targetTable
* @return
*/
NABoolean isOnKeyTo(const JoinGraphTablePtr targetTable);
/**
* Get the other table involved in this equality set, that is not the one
* involved in the given half-pred.
* @param target
* @return
*/
JoinGraphTablePtr getOtherTable(JoinGraphHalfPredicatePtr target);
/**
* Get the half pred that is on the other side - not on key.
* @return
*/
JoinGraphHalfPredicatePtr getForeignKeySide();
/**
* The degree of the equality set is the number of join preds it covers.
* Since a join pred is from one table to all other tables in the equality set,
* the degree is equal to the number of halfPreds minus one.
* @return
*/
Int32 getDegree()
{
return halfPreds_.entries() - 1;
}
Int32 getKeySource()
{
if (keyDirection_ == 0)
return 1;
else
return 0;
}
/**
* Prepare the input text for the Dotty graphical graph viewer for this
* equality set.
* @param[out] to Output string.
*/
void dumpGraph(NAString& to);
private:
// Copy construction/assignment not defined.
JoinGraphEqualitySet(const JoinGraphEqualitySet&);
JoinGraphEqualitySet& operator=(const JoinGraphEqualitySet&);
private:
HalfPredicateList halfPreds_;
const NAString descriptorID_;
UInt32 maxExprSize_;
// int tempNumber_;
NABoolean isOnKey_;
Int32 keyDirection_;
}; // class JoinGraphEqualitySet
/**
* A join graph is a graph of tables and equi-join predicates, corresponding
* to a JBB of an MV or query.
* The nodes of the graph are the tables and the equality sets, while the
* edges are the half predicates.
* The QRJoinGraph class encapsulates the methods for building the graph
* from the descriptor classes, while the traversal of the graph is the
* responsibility of the HubIterator class.
*
* @see JoinGraphTable
* @see JoinGraphHalfPredicate
* @see JoinGraphEqualitySet
* @see QRJoinSubGraph
* @see HubIterator
*****************************************************************************
*/
class QRJoinGraph : public NAIntrusiveSharedPtrObject
{
friend class QRJoinSubGraph;
public:
/**
* Public constructor.
* @param heap Heap from which to allocate internal data members.
*/
QRJoinGraph(ADD_MEMCHECK_ARGS_DECL(CollHeap* heap))
: NAIntrusiveSharedPtrObject(ADD_MEMCHECK_ARGS_PASS(heap))
,heap_(heap)
,nextTable_(0)
,isSelfJoin_(FALSE)
,tableHashByID_(hashKey, INIT_HASH_SIZE_SMALL, TRUE, heap)
,equalitySets_(heap)
,tableArray_(heap, 10)
,name_(heap)
,hasGroupBy_(FALSE)
,hubSize_(0)
,tablesToReduce_(heap_)
,minimizedSubGraph_(NULL)
,sortedTables_(NULL)
,pos_(0)
{}
virtual ~QRJoinGraph();
// Accessors
////////////////////
/** Does this join graph include more than one instance of any table? */
NABoolean isSelfJoin() { return isSelfJoin_; }
/** Get the heap pointer. */
CollHeap* getHeap() { return heap_; }
/** How many tables are included in this join graph? (For self-joins, individual instances are counted) */
CollIndex entries() { return tableArray_.entries(); }
/** Mark that this join graph includes a GROUP BY node. */
void setGroupBy() { hasGroupBy_ = TRUE; }
/** Does this join graph include a GROUP BY node at the top? */
NABoolean hasGroupBy() { return hasGroupBy_; }
/** How many tables are in the hub? */
Int32 getHubSize() const { return hubSize_; }
/**
* Find the JoinGraphTable object from the table ID.
* @param id The descriptor ID of the table.
* @return Pointer to JoinGraphTablePtr object.
*/
JoinGraphTablePtr getTableByID(const NAString& id)
{
return tableHashByID_.getFirstValue(&id);
}
/** Find an equality set using its descriptor ID. */
JoinGraphEqualitySetPtr FindEqualitySetByID(const NAString& id);
/**
* Find the JoinGraphTable object from the table's ordinal number.
* @param ix The table's ordinal number - its index into the QRJoinGraph table array.
* @return Pointer to JoinGraphTablePtr object.
*/
JoinGraphTablePtr getTableByOrdinal(CollIndex ix)
{
return tableArray_[ix];
}
/**
* Get the list of equality sets in this join graph.
*/
EqualitySetList& getEqualitySets() { return equalitySets_; }
/**
* Get the number of tables in this join graph.
* @return
*/
CollIndex getNumberOfTables()
{
return nextTable_;
}
JoinGraphTableList& getTablesToReduce()
{
return tablesToReduce_;
}
QRJoinSubGraphPtr getMinimizedSubGraph()
{
return minimizedSubGraph_;
}
// Graph construction methods
/////////////////////////////////
/**
* Add a table to the join graph.
* @param tableElement A table element from the descriptor.
*/
void addTable(const QRTablePtr tableElement,
NABoolean isHub,
const BaseTableDetailsPtr baseTable);
/**
* Add a half-pred to the join graph.
* @param equalitySet Pointer to the equality set object.
* @param tablePtr Pointer to the table object.
* @param expr The half-pred expression.
* @param id The descriptor ID of the new half-pred.
*/
void addHalfPredicate(JoinGraphEqualitySetPtr equalitySet,
JoinGraphTablePtr tablePtr,
const QRElementPtr elementPtr,
const NAString& expr);
/**
* Add an equality set to the join graph from the descriptor data.
* @param predElement The descriptor element for the new equality set.
*/
void addEqualitySet(const QRJoinPredPtr predElement);
/**
* Analyze a JBB element from the descriptor, and build the entire join graph from it.
* @param jbb
*/
void initFromJBB(const QRJBBPtr jbb, MVDetailsPtr mv);
/**
* Reset the temp numbers of all tables to -1 before starting a new traversal of the join graph.
*/
void resetTempNumbers();
/** A heuristic method for finding a good table to start a connected graph walk. */
JoinGraphTablePtr getFirstTable();
/** Find a table that is connected to the subgraph, but not yet part of it. */
JoinGraphTablePtr getNextTable(QRJoinSubGraphPtr subGraph);
// Debugging stuff
////////////////////
/** Set a name to the join graph for the graphical representation. */
void setName(const NAString& name) { name_ = name; }
/** Get the name of the join graph. */
const NAString& getName() { return name_; }
/** Create a graphical representation of the join graph by using the DOT language. */
void dumpGraph(MVDetailsPtr mv);
private:
void shiftTable(CollIndex insertPos);
CollIndex shiftArray(const NAString name);
private:
// Copy construction/assignment not defined.
QRJoinGraph(const QRJoinGraph&);
QRJoinGraph& operator=(const QRJoinGraph&);
private:
CollHeap* heap_;
Int32 nextTable_;
NABoolean isSelfJoin_;
JoinGraphTableHash tableHashByID_;
EqualitySetList equalitySets_;
JoinGraphTableArray tableArray_;
NAString name_; // For debugging
NABoolean hasGroupBy_;
Int32 hubSize_;
JoinGraphTableList tablesToReduce_;
QRJoinSubGraphPtr minimizedSubGraph_;
JoinGraphTableList* sortedTables_; // Used for WA SQL generation
UInt32 pos_;
}; // class QRJoinGraph
/**
* A QRJoinSubGraph includes a subset of the tables of its parent join graph
* and all the equality sets that include at least two half-predicates on
* these tables.
* for loop sample use:
* QRJoinSubGraph sg;
* for(sg.reset(); sg.hasNext(); sg.advance()) ... getCurrent()...
*
* @see QRJoinGraph
* @see JoinGraphTable
* @see JoinGraphHalfPredicate
* @see JoinGraphEqualitySet
* @see HubIterator
*****************************************************************************
*/
class QRJoinSubGraph : public NAIntrusiveSharedPtrObject
{
public:
/**
* Public constructor.
* @param parent A pointer to the join graph this subgraph is a part of.
* @param heap Heap from which to allocate internal data members.
*/
QRJoinSubGraph(QRJoinGraphPtr parent, ADD_MEMCHECK_ARGS_DECL(CollHeap* heap))
: NAIntrusiveSharedPtrObject(ADD_MEMCHECK_ARGS_PASS(heap))
,parentGraph_(parent)
,subArray_(&parent->tableArray_, heap)
,graphHashKey_(heap)
,pos_(0)
,isSelfJoin_(FALSE)
,hasGroupBy_(FALSE)
,stillUsed_(FALSE)
,fastKey_(heap)
,selfJoinHandler_(NULL)
{}
/**
* Copy construction IS defined for this class.
*/
QRJoinSubGraph(const QRJoinSubGraph& other, ADD_MEMCHECK_ARGS_DECL(CollHeap* heap))
: NAIntrusiveSharedPtrObject(ADD_MEMCHECK_ARGS_PASS(heap))
,parentGraph_(other.parentGraph_)
,subArray_(other.subArray_)
,graphHashKey_(heap)
,pos_(0)
,isSelfJoin_(other.isSelfJoin_)
,hasGroupBy_(other.hasGroupBy_)
,stillUsed_(FALSE)
,fastKey_(heap)
,selfJoinHandler_(NULL)
{}
virtual ~QRJoinSubGraph()
{}
// Mutators
/** Add a table to the join subgraph. */
void addTable(JoinGraphTablePtr table);
/** Remove a table from this join subgraph. */
void removeTable(JoinGraphTablePtr table);
/** Add all the tables in the join graph to this subgraph. */
void addAllTables();
/** Does this subgraph contain that table? */
NABoolean contains(JoinGraphTablePtr table)
{
return subArray_.contains(table->getOrdinalNumber());
}
/** Return the pointer to the parent JoinGraph. */
QRJoinGraphPtr getParentGraph()
{
return parentGraph_;
}
/** equals operator. */
NABoolean operator==(const QRJoinSubGraph& other)
{
return subArray_ == other.subArray_ &&
hasGroupBy_ == other.hasGroupBy_;
}
void updateTables(const QRJoinSubGraphPtr other)
{
subArray_ = other->subArray_;
}
/** Mark that this subgraph includes a GROUP BY node. */
void setGroupBy()
{
hasGroupBy_ = TRUE;
graphHashKey_ = ""; // Invalidate hash key.
fastKey_ = ""; // Invalidate hash key.
}
/** Does this subgraph include a GROUP BY node? */
NABoolean hasGroupBy() { return hasGroupBy_; }
// Mark that this subGraph is being used for the rewrite instructions
void setStillUsed(NABoolean used)
{ stillUsed_ = used; }
NABoolean stillUsed()
{ return stillUsed_; }
/**
* Compute the MVMemo hash key for the contained sub-graph.
* @return the hash key text.
*/
const QRJoinSubGraphMapPtr getSubGraphMap(OperationType op);
// Methods for iterating over the contained tables
///////////////////////////////////////////////////////
void reset() { pos_ = 0; }
NABoolean hasNext() { return subArray_.nextUsedFast(pos_); }
void advance() { pos_++; }
JoinGraphTablePtr getCurrent() { return subArray_.element(pos_); }
CollIndex entries() { return subArray_.entries(); }
/**
* Calculate the "fastKey" - a quick internal hash key based on the used tables
* and groupby flag. Internal means that it uses the table IDs, so can only
* be used for comparisons on the same descriptor.
*/
void calcFastKey();
/**
* Get the FastKey hash string.
* @return
*/
const NAString* getFastKey()
{
// If we have not already calculated the fastKey, do it now.
if (fastKey_ == "")
calcFastKey();
return &fastKey_;
}
/**
* Is the subGraph using all the hub tables in the full join graph?
* @return
*/
NABoolean isFull() const
{
return subArray_.entries() == parentGraph_->getHubSize() &&
hasGroupBy_ == parentGraph_->hasGroupBy();
}
/**
* Does this subgraph contain a self-join?
* @return
*/
NABoolean isSelfJoin()
{
return isSelfJoin_;
}
void setSelfJoin()
{
isSelfJoin_ = TRUE;
}
/**
*
* @return
*/
SelfJoinHandlerPtr getSelfJoinHandler()
{
return selfJoinHandler_;
}
void doEqualitySetsPart(NAString& hashKey) const;
protected:
void doTablesPart(NAString& hashKey, QRJoinSubGraphMapPtr map);
// Assignment NOT defined for this class.
QRJoinSubGraph& operator=(const QRJoinSubGraph&);
private:
QRJoinGraphPtr parentGraph_;
JoinGraphTableSubArray subArray_;
NAString graphHashKey_;
CollIndex pos_;
NABoolean isSelfJoin_;
NABoolean hasGroupBy_;
NABoolean stillUsed_;
NAString fastKey_;
SelfJoinHandlerPtr selfJoinHandler_;
}; // class QRJoinSubGraph
/**
*
*
*
*
*
*/
class QRJoinSubGraphMap : public NAIntrusiveSharedPtrObject
{
public:
/**
* Public constructor.
* @param parent A pointer to the join graph this subgraph is a part of.
* @param heap Heap from which to allocate internal data members.
*/
QRJoinSubGraphMap(QRJoinSubGraphPtr subGraph, NABoolean isMV, CollIndex size,
ADD_MEMCHECK_ARGS_DECL(CollHeap* heap))
: NAIntrusiveSharedPtrObject(ADD_MEMCHECK_ARGS_PASS(heap))
,subGraph_(subGraph)
,hashKey_(heap)
,tableMapping_(heap, size)
,indexHashByID_(hashKey, INIT_HASH_SIZE_SMALL, TRUE, heap) // Pass NAString::hashKey
,isMV_(isMV)
,mvDetails_(NULL)
,isACopy_(FALSE)
,shiftVector_(heap)
{
subGraph->setStillUsed(TRUE);
}
// Copy Ctor.
QRJoinSubGraphMap(const QRJoinSubGraphMap& other, ADD_MEMCHECK_ARGS_DECL(CollHeap* heap));
virtual ~QRJoinSubGraphMap();
void addTable(CollIndex ix, const JoinGraphTablePtr table);
/**
* The query side translation: find the hash key index for a particular table.
* @param id The query descriptor ID of the table.
* @return The query hash key index, -1 if not found.
*/
Int32 getIndexForTable(const NAString& id) const;
/**
* The MV side translation: find the table information for its index.
* @param ix The table index in the MV hash key.
* @return Pointer to the table information.
*/
const JoinGraphTablePtr getTableForIndex(CollIndex ix) const;
/**
* Is the subGraph using all the tables in the full joinn graph?
* @return
*/
NABoolean isFull() const
{
return subGraph_->isFull();
}
void setHashKey(const NAString& key)
{
hashKey_ = key;
}
const NAString& getHashKey()
{
return hashKey_;
}
QRJoinSubGraphPtr getSubGraph()
{
return subGraph_;
}
NABoolean contains(const NAString& id)
{
return indexHashByID_.contains(&id);
}
void setMVDetails(MVDetailsPtr mv)
{
mvDetails_ = mv;
}
MVDetailsPtr getMVDetails() const
{
return mvDetails_;
}
/** Does this subgraph include a GROUP BY node? */
NABoolean hasGroupBy() { return subGraph_->hasGroupBy(); }
// Self-Joins
///////////////////
/**
* Does the join subgraph this map is based on include more than
* a single instance of any of its tables?
*/
NABoolean isSelfJoin()
{
return subGraph_->isSelfJoin();
// Return FALSE here in order to disable SelfJoin handling.
//return FALSE;
}
void prepareForSelfJoinWork();
/**
* Does the last subgraph have an equivalent MVMemo hash key for its self-join?
*/
NABoolean hasNextEquivalentMap() const;
/**
* Get the next equivalent MVMemo hash key for the current self-join subgraph.
*/
QRJoinSubGraphMapPtr nextEquivalentMap() const;
const NAString& getShiftVector()
{
return shiftVector_;
}
void restoreTempNumbers() const;
private:
class UnsignedInteger : public NABasicObject
{
public:
// Default constructor
UnsignedInteger()
: data_(0)
{}
UnsignedInteger(CollIndex data)
: data_(data)
{}
virtual ~UnsignedInteger()
{}
// Copy construction
UnsignedInteger(const UnsignedInteger& other)
: data_(other.data_)
{}
// Assignment operator
UnsignedInteger& operator=(const UnsignedInteger& other)
{ data_ = other.data_; return *this; }
NABoolean operator==(const UnsignedInteger& other)
{ return data_ == other.data_; }
CollIndex getInt()
{ return data_; }
private:
CollIndex data_;
}; // Internal class UnsignedInteger
typedef NAHashDictionary<const NAString, UnsignedInteger> IndexHash;
typedef NAHashDictionaryIterator<const NAString, UnsignedInteger> IndexHashIterator;
QRJoinSubGraphPtr subGraph_;
NAString hashKey_;
JoinGraphTableArray tableMapping_;
IndexHash indexHashByID_;
NABoolean isMV_;
MVDetailsPtr mvDetails_;
NABoolean isACopy_; // Was this object created using the copy constructor?
NAString shiftVector_; // For debugging only.
}; // class QRJoinSubGraphMap
/**
* Takes a join graph, generates a stream of unique subgraphs of it, and
* produces the hash keys of those subgraphs.
* For now, Produces only connected subgraphs - graphs with cross products
* are not handled yet.
* Has two modes of operation: for insert and search operations in MVMemo.
*
* @see QRJoinGraph
* @see QRJoinSubGraph
* @see MVMemo
* \todo Produce equivalent expressions for self-joins.
* \todo Produce more expressions for join graphs with circular join predicates.
*****************************************************************************
*/
class HubIterator : public NAIntrusiveSharedPtrObject
{
public:
/**
* Public constructor.
* @param joinGraph The join graph to iterate on.
* @param isForInsert Operation mode: insert or search?
* @param heap Heap from which to allocate internal data members.
*/
HubIterator(QRJoinGraphPtr joinGraph,
OperationType isForInsert,
ADD_MEMCHECK_ARGS_DECL(CollHeap* heap))
: NAIntrusiveSharedPtrObject(ADD_MEMCHECK_ARGS_PASS(heap))
,joinGraph_(joinGraph)
,opType_(isForInsert)
,subGraphsVisited_(hashKey, INIT_HASH_SIZE_LARGE, FALSE, heap)
,subGraphsReady_(heap, 100)
,subGraphsToAvoid_(hashKey, INIT_HASH_SIZE_LARGE, FALSE, heap)
,currentSubgraph_(NULL)
,usedGroupBy_(FALSE)
{}
virtual ~HubIterator();
/**
* There are probably more results if there are still more subgraphs in
* the ready list. Its only probably true because the remaining subgraphs
* may be duplicates. However, if this method returns FALSE, then its final.
*/
NABoolean hasNext()
{
assertLogAndThrow(CAT_MVMEMO_JOINGRAPH, LL_MVQR_FAIL,
subGraphsVisited_.entries() > 0, QRLogicException,
"This method should not be called before trying any subgraphs.");
// Check if we have subgraphs to work on.
if (subGraphsReady_.entries() > 0)
return TRUE;
// Did we check the top subgraph with the GroupBy flag yet?
if (joinGraph_->hasGroupBy() && !usedGroupBy_)
return TRUE;
return FALSE;
}
/**
* Initialize the iterator: populate the ready list with all the single-table
* subgraphs of the join graph.
*/
void init();
/**
* Return the next subgraph to search/insert.
*/
const QRJoinSubGraphPtr nextSubGraph();
const QRJoinSubGraphPtr getMinimizedSubGraph();
/**
* Computes the supersets of subGraph that include a single additional table
* that is conneted to it, and add them to the ready list. \par
* 1. For each table included in the subgraph, find all the connected tables
* that are not yet part of the subgraph, and add them to a set of
* unique entries. \par
* 2. For each of the tables in the resulting set, create a new subgraph from
* the current subgraph plus that table, and add it to the ready list. \par
* @param subGraph The current subgraph.
*/
void getNextLevelSupersets(QRJoinSubGraphPtr subGraph);
/**
* The current join graph uses an MV as one of its tables.
* Rewrite the join graph to use the MVs query instead.
*/
void rewriteJoinGraph(const MVDetailsPtr mvDetails) {}
/**
* During a search operation, report that the current subgraph was not found
* in MVMemo, and so it and its supersets should be avoided.
*/
void reportAsMissing();
/**
* Does this join graph have too many self-joins?
* @return
*/
NABoolean isSelfJoinTooBig();
/**
* Create a subGraph for the full join graph.
* @return
*/
const QRJoinSubGraphPtr getFullSubGraph();
private:
// Copy construction/assignment not defined.
HubIterator(const HubIterator&);
HubIterator& operator=(const HubIterator&);
private:
// Max threshold for self-join permutation work.
// If the join graph is more complex than this, MVMemo will skip self-join work.
// and only same order queries will be matched.
// Biggest Yotta query I've seen is 4x4x2 = 1,152
// At 8x2 > 80,000 we run out of memory and crash.
// 6000 allows for a 5x4x2 self-join (5760).
enum { MAX_SELFJOIN_PERMUTATIONS = 6000 };
QRJoinGraphPtr joinGraph_;
OperationType opType_;
/** This hash table remembers every subgraph we tried. Used to detect duplicates. */
SubGraphHash subGraphsVisited_;
/** The ready list contains subgraphs that are ready to be tested. */
SubGraphList subGraphsReady_;
/** Subgraphs that were not found in MVMemo during search, and so they and their supersets should be skipped. */
SubGraphHash subGraphsToAvoid_;
/** The last subgraph that was returned. */
QRJoinSubGraphPtr currentSubgraph_;
// Did the iterator already produce the subgraph with the GROUP BY node?
NABoolean usedGroupBy_;
}; // class HubIterator
#endif