?? mitab_indfile.cpp
字號(hào):
// m_poDataBlock is now positioned at the beginning of the key entries
return 0;
}
/**********************************************************************
* TABINDNode::GotoNodePtr()
*
* Move to the specified node ptr, and read the new node data from the file.
*
* This is just a cover funtion on top of InitNode()
**********************************************************************/
int TABINDNode::GotoNodePtr(GInt32 nNewNodePtr)
{
// First flush current changes if any.
if ((m_eAccessMode == TABWrite || m_eAccessMode == TABReadWrite) &&
m_poDataBlock && m_poDataBlock->CommitToFile() != 0)
return -1;
CPLAssert(nNewNodePtr % 512 == 0);
// Then move to the requested location.
return InitNode(m_fp, nNewNodePtr, m_nKeyLength, m_nSubTreeDepth,
m_bUnique);
}
/**********************************************************************
* TABINDNode::ReadIndexEntry()
*
* Read the key value and record/node ptr for the specified index entry
* inside the current node data.
*
* nEntryNo is the 0-based index of the index entry that we are interested
* in inside the current node.
*
* Returns the record/node ptr, and copies the key value inside the
* buffer pointed to by *pKeyValue... this assumes that *pKeyValue points
* to a buffer big enough to hold the key value (m_nKeyLength bytes).
* If pKeyValue == NULL, then this parameter is ignored and the key value
* is not copied.
**********************************************************************/
GInt32 TABINDNode::ReadIndexEntry(int nEntryNo, GByte *pKeyValue)
{
GInt32 nRecordPtr = 0;
if (nEntryNo >= 0 && nEntryNo < m_numEntriesInNode)
{
if (pKeyValue)
{
m_poDataBlock->GotoByteInBlock(12 + nEntryNo*(m_nKeyLength+4));
m_poDataBlock->ReadBytes(m_nKeyLength, pKeyValue);
}
else
{
m_poDataBlock->GotoByteInBlock(12 + nEntryNo*(m_nKeyLength+4)+
m_nKeyLength);
}
nRecordPtr = m_poDataBlock->ReadInt32();
}
return nRecordPtr;
}
/**********************************************************************
* TABINDNode::IndexKeyCmp()
*
* Compare the specified index entry with the key value, and
* return 0 if equal, an integer less than 0 if key is smaller than
* index entry, and an integer greater than 0 if key is bigger than
* index entry.
*
* nEntryNo is the 0-based index of the index entry that we are interested
* in inside the current node.
**********************************************************************/
int TABINDNode::IndexKeyCmp(GByte *pKeyValue, int nEntryNo)
{
CPLAssert(pKeyValue);
CPLAssert(nEntryNo >= 0 && nEntryNo < m_numEntriesInNode);
m_poDataBlock->GotoByteInBlock(12 + nEntryNo*(m_nKeyLength+4));
return memcmp(pKeyValue, m_poDataBlock->GetCurDataPtr(), m_nKeyLength);
}
/**********************************************************************
* TABINDNode::SetFieldType()
*
* Sets the field type for the current index and recursively set all
* children as well.
* This information will then be used in building the key values, etc.
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABINDNode::SetFieldType(TABFieldType eType)
{
if (m_fp == NULL)
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABINDNode::SetFieldType(): File has not been opened yet!");
return -1;
}
/*-----------------------------------------------------------------
* Validate field type with key length
*----------------------------------------------------------------*/
if ((eType == TABFInteger && m_nKeyLength != 4) ||
(eType == TABFSmallInt && m_nKeyLength != 2) ||
(eType == TABFFloat && m_nKeyLength != 8) ||
(eType == TABFDecimal && m_nKeyLength != 8) ||
(eType == TABFDate && m_nKeyLength != 4) ||
(eType == TABFTime && m_nKeyLength != 4) ||
(eType == TABFDateTime && m_nKeyLength != 8) ||
(eType == TABFLogical && m_nKeyLength != 4) )
{
CPLError(CE_Failure, CPLE_IllegalArg,
"Index key length (%d) does not match field type (%s).",
m_nKeyLength, TABFIELDTYPE_2_STRING(eType) );
return -1;
}
m_eFieldType = eType;
/*-----------------------------------------------------------------
* Pass the field type info to child nodes
*----------------------------------------------------------------*/
if (m_poCurChildNode)
return m_poCurChildNode->SetFieldType(eType);
return 0;
}
/**********************************************************************
* TABINDNode::FindFirst()
*
* Start a new search in this node and its children for a key value.
* If the index is not unique, then FindNext() can be used to return
* the other values that correspond to the key.
*
* Return value:
* - the key's corresponding record number in the .DAT file (greater than 0)
* - 0 if the key was not found
* - or -1 if an error happened
**********************************************************************/
GInt32 TABINDNode::FindFirst(GByte *pKeyValue)
{
if (m_poDataBlock == NULL)
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABINDNode::Search(): Node has not been initialized yet!");
return -1;
}
/*-----------------------------------------------------------------
* Unless something has been broken, this method will be called by our
* parent node after it has established that we are the best candidate
* to contain the first instance of the key value. So there is no
* need to look in the previous or next nodes in the chain... if the
* value is not found in the current node block then it is not present
* in the index at all.
*
* m_nCurIndexEntry will be used to keep track of the search pointer
* when FindNext() will be used.
*----------------------------------------------------------------*/
m_nCurIndexEntry = 0;
if (m_nSubTreeDepth == 1)
{
/*-------------------------------------------------------------
* Leaf node level... we look for an exact match
*------------------------------------------------------------*/
while(m_nCurIndexEntry < m_numEntriesInNode)
{
int nCmpStatus = IndexKeyCmp(pKeyValue, m_nCurIndexEntry);
if (nCmpStatus > 0)
{
/* Not there yet... (pKey > IndexEntry) */
m_nCurIndexEntry++;
}
else if (nCmpStatus == 0)
{
/* Found it! Return the record number */
return ReadIndexEntry(m_nCurIndexEntry, NULL);
}
else
{
/* Item does not exist... return 0 */
return 0;
}
}
}
else
{
/*-------------------------------------------------------------
* Index Node: Find the child node that is the best candidate to
* contain the value
*
* In the index tree at the node level, for each node entry inside
* the parent node, the key value (in the parent) corresponds to
* the value of the first key that you will find when you access
* the corresponding child node.
*
* This means that to find the child that contains the searched
* key, we look for the first index key >= pKeyValue and the child
* node that we are looking for is the one that precedes it.
*
* If the first key in the list is >= pKeyValue then this means
* that the pKeyValue does not exist in our children and we just
* return 0. We do not bother searching the previous node at the
* same level since this is the responsibility of our parent.
*
* The same way if the last indexkey in this node is < pKeyValue
* we won't bother searching the next node since this should also
* be taken care of by our parent.
*------------------------------------------------------------*/
while(m_nCurIndexEntry < m_numEntriesInNode)
{
int nCmpStatus = IndexKeyCmp(pKeyValue, m_nCurIndexEntry);
if (nCmpStatus > 0 && m_nCurIndexEntry+1 < m_numEntriesInNode)
{
/* Not there yet... (pKey > IndexEntry) */
m_nCurIndexEntry++;
}
else
{
/*-----------------------------------------------------
* We either found an indexkey >= pKeyValue or reached
* the last entry in this node... still have to decide
* what we're going to do...
*----------------------------------------------------*/
if (nCmpStatus < 0 && m_nCurIndexEntry == 0)
{
/*-------------------------------------------------
* First indexkey in block is > pKeyValue...
* the key definitely does not exist in our children.
* However, we still want to drill down the rest of the
* tree because this function is also used when looking
* for a node to insert a new value.
*-------------------------------------------------*/
// Nothing special to do... just continue processing.
}
/*-----------------------------------------------------
* If we found an node for which pKeyValue < indexkey
* (or pKeyValue <= indexkey for non-unique indexes) then
* we access the preceding child node.
*
* Note that for indexkey == pKeyValue in non-unique indexes
* we also check in the preceding node because when keys
* are not unique then there are chances that the requested
* key could also be found at the end of the preceding node.
* In this case, if we don't find the key in the preceding
* node then we'll do a second search in the current node.
*----------------------------------------------------*/
int numChildrenToVisit=1;
if (m_nCurIndexEntry > 0 &&
(nCmpStatus < 0 || (nCmpStatus==0 && !m_bUnique)) )
{
m_nCurIndexEntry--;
if (nCmpStatus == 0)
numChildrenToVisit = 2;
}
/*-----------------------------------------------------
* OK, now it's time to load/access the candidate child nodes.
*----------------------------------------------------*/
int nRetValue = 0;
for(int iChild=0; nRetValue==0 &&
iChild<numChildrenToVisit; iChild++)
{
// If we're doing a second pass then jump to next entry
if (iChild > 0)
m_nCurIndexEntry++;
int nChildNodePtr = ReadIndexEntry(m_nCurIndexEntry, NULL);
if (nChildNodePtr == 0)
{
/* Invalid child node??? */
nRetValue = 0;
continue;
}
else if (m_poCurChildNode == NULL)
{
/* Child node has never been initialized...do it now!*/
m_poCurChildNode = new TABINDNode(m_eAccessMode);
if ( m_poCurChildNode->InitNode(m_fp, nChildNodePtr,
m_nKeyLength,
m_nSubTreeDepth-1,
m_bUnique,
m_poBlockManagerRef,
this) != 0 ||
m_poCurChildNode->SetFieldType(m_eFieldType)!=0)
{
// An error happened... and was already reported
return -1;
}
}
if (m_poCurChildNode->GotoNodePtr(nChildNodePtr) != 0)
{
// An error happened and has already been reported
return -1;
}
nRetValue = m_poCurChildNode->FindFirst(pKeyValue);
}/*for iChild*/
return nRetValue;
}/*else*/
}/*while numEntries*/
// No node was found that contains the key value.
// We should never get here... only leaf nodes should return 0
CPLAssert(FALSE);
return 0;
}
return 0; // Not found
}
/**********************************************************************
* TABINDNode::FindNext()
*
* Continue the search previously started by FindFirst() in this node
* and its children for a key value.
*
* Return value:
* - the key's corresponding record number in the .DAT file (greater than 0)
* - 0 if the key was not found
* - or -1 if an error happened
**********************************************************************/
GInt32 TABINDNode::FindNext(GByte *pKeyValue)
{
if (m_poDataBlock == NULL)
{
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -