Renamed version4 to flaim and version5 to xflaim
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
811
xflaim/src/ddcreate.cpp
Normal file
811
xflaim/src/ddcreate.cpp
Normal file
@@ -0,0 +1,811 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Desc: Routines to service creation of a database dictionary.
|
||||
//
|
||||
// Tabs: 3
|
||||
//
|
||||
// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of version 2 of the GNU General Public
|
||||
// License as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, contact Novell, Inc.
|
||||
//
|
||||
// To contact Novell about this file by physical or electronic mail,
|
||||
// you may find current contact information at www.novell.com
|
||||
//
|
||||
// $Id: ddcreate.cpp 3111 2006-01-19 13:10:50 -0700 (Thu, 19 Jan 2006) dsanders $
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
// Internal Static Routines
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Read in LFH headers.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::dictReadLFH( void)
|
||||
{
|
||||
RCODE rc = NE_XFLM_OK;
|
||||
LFILE * pLFile;
|
||||
F_COLLECTION * pCollection;
|
||||
F_CachedBlock * pSCache;
|
||||
FLMBOOL bReleaseCache = FALSE;
|
||||
F_BLK_HDR * pBlkHdr;
|
||||
FLMUINT uiBlkAddress;
|
||||
FLMUINT uiPos;
|
||||
FLMUINT uiEndPos;
|
||||
FLMUINT uiBlkSize = m_pDatabase->m_uiBlockSize;
|
||||
LFILE TmpLFile;
|
||||
F_COLLECTION TmpCollection;
|
||||
|
||||
f_memset( &TmpLFile, 0, sizeof( LFILE));
|
||||
f_memset( &TmpCollection, 0, sizeof( F_COLLECTION));
|
||||
|
||||
uiBlkAddress =
|
||||
(FLMUINT)m_pDatabase->m_lastCommittedDbHdr.ui32FirstLFBlkAddr;
|
||||
while (uiBlkAddress)
|
||||
{
|
||||
if (RC_BAD( rc = m_pDatabase->getBlock( this, NULL,
|
||||
uiBlkAddress, NULL, &pSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bReleaseCache = TRUE;
|
||||
|
||||
pBlkHdr = pSCache->m_pBlkHdr;
|
||||
uiPos = SIZEOF_STD_BLK_HDR;
|
||||
uiEndPos = blkGetEnd( uiBlkSize, SIZEOF_STD_BLK_HDR, pBlkHdr);
|
||||
|
||||
// Read through all of the logical file definitions in the block
|
||||
|
||||
for( ; uiPos + sizeof( F_LF_HDR) <= uiEndPos; uiPos += sizeof( F_LF_HDR))
|
||||
{
|
||||
F_LF_HDR * pLfHdr = (F_LF_HDR *)((FLMBYTE *)(pBlkHdr) + uiPos);
|
||||
eLFileType eLfType = (eLFileType)pLfHdr->ui32LfType;
|
||||
|
||||
// Have to fix up the offsets later when they are read in
|
||||
|
||||
if (eLfType == XFLM_LF_INVALID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Populate the LFILE in the dictionary, if one has been set up.
|
||||
|
||||
if (eLfType == XFLM_LF_INDEX)
|
||||
{
|
||||
FSLFileIn( (FLMBYTE *)pLfHdr,
|
||||
&TmpLFile, NULL, uiBlkAddress, uiPos);
|
||||
|
||||
if (RC_OK( m_pDict->getIndex( TmpLFile.uiLfNum, &pLFile,
|
||||
NULL, TRUE)))
|
||||
{
|
||||
f_memcpy( pLFile, &TmpLFile, sizeof( LFILE));
|
||||
}
|
||||
|
||||
// LFILE better have a non-zero root block.
|
||||
|
||||
if (!TmpLFile.uiRootBlk)
|
||||
{
|
||||
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Better be a container
|
||||
|
||||
flmAssert( eLfType == XFLM_LF_COLLECTION);
|
||||
|
||||
FSLFileIn( (FLMBYTE *)pLfHdr,
|
||||
&TmpCollection.lfInfo, &TmpCollection, uiBlkAddress, uiPos);
|
||||
|
||||
if (RC_OK( m_pDict->getCollection( TmpCollection.lfInfo.uiLfNum,
|
||||
&pCollection, TRUE)))
|
||||
{
|
||||
f_memcpy( pCollection, &TmpCollection, sizeof( F_COLLECTION));
|
||||
}
|
||||
|
||||
// LFILE better have a non-zero root block.
|
||||
|
||||
if (!TmpCollection.lfInfo.uiRootBlk)
|
||||
{
|
||||
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the next block in the chain
|
||||
|
||||
uiBlkAddress = (FLMUINT)pBlkHdr->ui32NextBlkInChain;
|
||||
ScaReleaseCache( pSCache, FALSE);
|
||||
bReleaseCache = FALSE;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (bReleaseCache)
|
||||
{
|
||||
ScaReleaseCache( pSCache, FALSE);
|
||||
}
|
||||
|
||||
return( rc );
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Read in all element, attribute, index, or collection definitions - as
|
||||
specified in uiDictType.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::dictReadDefs(
|
||||
FLMUINT uiDictType)
|
||||
{
|
||||
RCODE rc = NE_XFLM_OK;
|
||||
F_DataVector key;
|
||||
LFILE * pLFile;
|
||||
IXD * pIxd;
|
||||
F_Btree * pbTree = NULL;
|
||||
FLMBYTE ucKeyBuf [MAX_KEY_SIZ];
|
||||
FLMUINT uiKeyLen;
|
||||
FLMUINT uiFoundDictType;
|
||||
FLMUINT uiLowest;
|
||||
FLMUINT uiHighest;
|
||||
FLMUINT uiDictNum;
|
||||
IXKeyCompare compareObject;
|
||||
|
||||
if (RC_BAD( rc = m_pDict->getIndex( XFLM_DICT_NUMBER_INDEX, &pLFile, &pIxd)))
|
||||
{
|
||||
RC_UNEXPECTED_ASSERT( rc);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// First determine the low and high field numbers.
|
||||
|
||||
// If the LFILE is not yet set up, the index has not yet been
|
||||
// created, so there will be no definitions to read. This will
|
||||
// be the case when we are first creating the dictionary. We have
|
||||
// started a transaction, and it is trying to read in the definitions
|
||||
// but there are none.
|
||||
|
||||
flmAssert( pLFile->uiRootBlk);
|
||||
|
||||
// Get a btree
|
||||
|
||||
if (RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pbTree)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Open the B-Tree
|
||||
|
||||
compareObject.setIxInfo( this, pIxd);
|
||||
compareObject.setCompareNodeIds( FALSE);
|
||||
compareObject.setCompareDocId( FALSE);
|
||||
compareObject.setSearchKey( &key);
|
||||
|
||||
if (RC_BAD( rc = pbTree->btOpen( this, pLFile, FALSE, FALSE,
|
||||
&compareObject)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = key.setUINT( 0, uiDictType)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = key.outputKey( pIxd, 0,
|
||||
ucKeyBuf, sizeof( ucKeyBuf), &uiKeyLen, SEARCH_KEY_FLAG)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Position to the first key, if any
|
||||
|
||||
if (RC_BAD( rc = pbTree->btLocateEntry( ucKeyBuf, sizeof( ucKeyBuf),
|
||||
&uiKeyLen, XFLM_INCL, NULL)))
|
||||
{
|
||||
|
||||
// May not have found anything.
|
||||
|
||||
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
|
||||
{
|
||||
rc = NE_XFLM_OK;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
key.reset();
|
||||
|
||||
if (RC_BAD( rc = key.inputKey( pIxd, ucKeyBuf, uiKeyLen)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// See if we went past the last key of this type.
|
||||
|
||||
if (RC_BAD( rc = key.getUINT( 0, &uiFoundDictType)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (uiFoundDictType != uiDictType)
|
||||
{
|
||||
goto Exit; // Will return NE_XFLM_OK
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = key.getUINT( 1, &uiLowest)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
uiHighest = uiLowest;
|
||||
|
||||
// Position to the end of keys of this type
|
||||
|
||||
key.reset();
|
||||
if (RC_BAD( rc = key.setUINT( 0, uiDictType)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = key.setUINT( 1, 0xFFFFFFFF)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = key.outputKey( pIxd, 0,
|
||||
ucKeyBuf, sizeof( ucKeyBuf), &uiKeyLen, SEARCH_KEY_FLAG)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Position to just past the specified key.
|
||||
|
||||
if (RC_BAD( rc = pbTree->btLocateEntry( ucKeyBuf, sizeof( ucKeyBuf),
|
||||
&uiKeyLen, XFLM_EXCL, NULL)))
|
||||
{
|
||||
|
||||
// May not have found anything, in which case we need to
|
||||
// position to the last key in the index.
|
||||
|
||||
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
|
||||
{
|
||||
if (RC_BAD( rc = pbTree->btLastEntry( ucKeyBuf, sizeof( ucKeyBuf),
|
||||
&uiKeyLen)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Backup one key - since we will have gone just beyond
|
||||
// keys of this type.
|
||||
|
||||
if (RC_BAD( rc = pbTree->btPrevEntry( ucKeyBuf, sizeof( ucKeyBuf),
|
||||
&uiKeyLen)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point we better be positioned on the last key of this type
|
||||
|
||||
key.reset();
|
||||
|
||||
if (RC_BAD( rc = key.inputKey( pIxd, ucKeyBuf, uiKeyLen)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = key.getUINT( 0, &uiFoundDictType)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// See if we went past the last key of this type - should not
|
||||
// be possible, unless there is a corruption.
|
||||
|
||||
if (uiFoundDictType != uiDictType)
|
||||
{
|
||||
rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = key.getUINT( 1, &uiHighest)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// uiHighest better be >= uiLowest or we have
|
||||
// b-tree corruption.
|
||||
|
||||
if (uiHighest < uiLowest)
|
||||
{
|
||||
rc = RC_SET_AND_ASSERT( NE_XFLM_BTREE_ERROR);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Pre-allocate the tables
|
||||
|
||||
if (uiDictType == ELM_ELEMENT_TAG)
|
||||
{
|
||||
if (RC_BAD( rc = m_pDict->allocElementTable( uiLowest, uiHighest)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else if (uiDictType == ELM_ATTRIBUTE_TAG)
|
||||
{
|
||||
if (RC_BAD( rc = m_pDict->allocAttributeTable( uiLowest, uiHighest)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else if (uiDictType == ELM_INDEX_TAG)
|
||||
{
|
||||
if (RC_BAD( rc = m_pDict->allocIndexTable( uiLowest, uiHighest)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else if (uiDictType == ELM_PREFIX_TAG)
|
||||
{
|
||||
if (RC_BAD( rc = m_pDict->allocPrefixTable( uiLowest, uiHighest)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else if (uiDictType == ELM_ENCDEF_TAG)
|
||||
{
|
||||
if (RC_BAD( rc = m_pDict->allocEncDefTable( uiLowest, uiHighest)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else // (uiDictType == ELM_COLLECTION_TAG)
|
||||
{
|
||||
flmAssert( uiDictType == ELM_COLLECTION_TAG);
|
||||
|
||||
if (RC_BAD( rc = m_pDict->allocCollectionTable( uiLowest, uiHighest)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Position back to the first key for this type
|
||||
|
||||
key.reset();
|
||||
if (RC_BAD( rc = key.setUINT( 0, uiDictType)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = key.outputKey( pIxd, 0,
|
||||
ucKeyBuf, sizeof( ucKeyBuf),
|
||||
&uiKeyLen, SEARCH_KEY_FLAG)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = pbTree->btLocateEntry( ucKeyBuf, sizeof( ucKeyBuf),
|
||||
&uiKeyLen, XFLM_INCL, NULL)))
|
||||
{
|
||||
|
||||
// May not have found anything.
|
||||
|
||||
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
|
||||
{
|
||||
rc = NE_XFLM_OK;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Loop through all of the keys of this dictionary type
|
||||
|
||||
for (;;)
|
||||
{
|
||||
key.reset();
|
||||
|
||||
if (RC_BAD( rc = key.inputKey( pIxd, ucKeyBuf, uiKeyLen)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// See if we went past the last key of this type.
|
||||
|
||||
if (RC_BAD( rc = key.getUINT( 0, &uiFoundDictType)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (uiFoundDictType != uiDictType)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the dictionary number
|
||||
|
||||
if (RC_BAD( rc = key.getUINT( 1, &uiDictNum)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// No need to process any more elements or attributes if the
|
||||
// dictionary number is in the extended range.
|
||||
|
||||
if ((uiDictType == ELM_ELEMENT_TAG &&
|
||||
uiDictNum >= FLM_LOW_EXT_ELEMENT_NUM) ||
|
||||
(uiDictType == ELM_ATTRIBUTE_TAG &&
|
||||
uiDictNum >= FLM_LOW_EXT_ATTRIBUTE_NUM))
|
||||
{
|
||||
if (uiDictType == ELM_ELEMENT_TAG)
|
||||
{
|
||||
m_pDict->m_pNameTable->m_bLoadedAllElements = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDict->m_pNameTable->m_bLoadedAllAttributes = FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = m_pDict->updateDict( this,
|
||||
uiDictType, key.getDocumentID(), 0,
|
||||
TRUE, FALSE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Go to the next key
|
||||
|
||||
if (RC_BAD( rc = pbTree->btNextEntry( ucKeyBuf,
|
||||
sizeof( ucKeyBuf),
|
||||
&uiKeyLen)))
|
||||
{
|
||||
|
||||
// May not have found anything.
|
||||
|
||||
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
|
||||
{
|
||||
rc = NE_XFLM_OK;
|
||||
break;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (pbTree)
|
||||
{
|
||||
gv_XFlmSysData.pBtPool->btpReturnBtree( &pbTree);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Open a dictionary by reading in all of the dictionary tables
|
||||
from the dictionaries.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::dictOpen( void)
|
||||
{
|
||||
RCODE rc = NE_XFLM_OK;
|
||||
|
||||
// At this point, better not be pointing to a dictionary.
|
||||
|
||||
flmAssert( !m_pDict);
|
||||
|
||||
// Should never get here for a temporary database.
|
||||
|
||||
flmAssert( !m_pDatabase->m_bTempDb);
|
||||
|
||||
// Allocate a new F_Dict object for reading the dictionary
|
||||
// into memory.
|
||||
|
||||
if ((m_pDict = f_new F_Dict) == NULL)
|
||||
{
|
||||
rc = RC_SET( NE_XFLM_MEM);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Allocate the name table
|
||||
|
||||
if (RC_BAD( rc = m_pDict->allocNameTable()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Add in all of the reserved dictionary tags to the name table.
|
||||
|
||||
if (RC_BAD( rc = m_pDict->getNameTable()->addReservedDictTags()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Allocate the fixed collections and indexes and set them up
|
||||
|
||||
if (RC_BAD( rc = m_pDict->setupPredefined(
|
||||
m_pDatabase->m_uiDefaultLanguage)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Read in the LFH's for the predefined stuff.
|
||||
|
||||
if (RC_BAD( rc = dictReadLFH()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If dictionary collection is not yet set up, do nothing.
|
||||
|
||||
if (m_pDict->m_pDictCollection->lfInfo.uiBlkAddress &&
|
||||
m_pDict->m_pDictCollection->lfInfo.uiOffsetInBlk)
|
||||
{
|
||||
|
||||
// Read in definitions in the following order:
|
||||
// 1) attribute definitions
|
||||
// 2) element definitions
|
||||
// 3) collection definitions
|
||||
// 4) index definitions
|
||||
// This guarantees that things will be defined by the
|
||||
// time they are referenced.
|
||||
|
||||
if (RC_BAD( rc = dictReadDefs( ELM_ATTRIBUTE_TAG)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = dictReadDefs( ELM_ELEMENT_TAG)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = dictReadDefs( ELM_COLLECTION_TAG)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = dictReadDefs( ELM_INDEX_TAG)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = dictReadDefs( ELM_PREFIX_TAG)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = dictReadDefs( ELM_ENCDEF_TAG)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Must read LFHs to get the LFILE information for the
|
||||
// collections and indexes we have just added.
|
||||
|
||||
if (RC_BAD( rc = dictReadLFH()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
m_pDict->getNameTable()->sortTags();
|
||||
|
||||
if (m_pDatabase)
|
||||
{
|
||||
m_pDict->m_bInLimitedMode = m_pDatabase->inLimitedMode();
|
||||
}
|
||||
// VISIT: Should we assume limited mode if we don't have a database file ?
|
||||
|
||||
Exit:
|
||||
|
||||
if (RC_BAD( rc) && m_pDict)
|
||||
{
|
||||
m_pDict->Release();
|
||||
m_pDict = NULL;
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Creates a new dictionary for a database.
|
||||
This occurs on database create and on a dictionary change.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::createNewDict( void)
|
||||
{
|
||||
RCODE rc = NE_XFLM_OK;
|
||||
|
||||
// Unlink the DB from the current F_Dict object, if any.
|
||||
|
||||
if (m_pDict)
|
||||
{
|
||||
m_pDatabase->lockMutex();
|
||||
unlinkFromDict();
|
||||
m_pDatabase->unlockMutex();
|
||||
}
|
||||
|
||||
// Allocate a new F_Dict object for the new dictionary we
|
||||
// are going to create.
|
||||
|
||||
if (RC_BAD( rc = dictOpen()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Update the F_Db flags to indicate that the dictionary
|
||||
// was updated.
|
||||
|
||||
m_uiFlags |= FDB_UPDATED_DICTIONARY;
|
||||
|
||||
// Create a special document in the dictionary to hold
|
||||
// the next element, next attribute, next index, and next
|
||||
// collection numbers.
|
||||
|
||||
if (RC_BAD( rc = m_pDict->createNextDictNums( this)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Add data dictionary records to the data dictionary.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::dictCreate(
|
||||
const char * pszDictPath, // Name of dictionary file. This is only
|
||||
// used if dictBuf is NULL. If both
|
||||
// dictPath and dictBuf are NULL, the
|
||||
// database will be created with an empty
|
||||
// dictionary
|
||||
const char * pszDictBuf) // Buffer containing dictionary in ASCII
|
||||
// GEDCOM If NULL pszDictPath will be used
|
||||
{
|
||||
RCODE rc = NE_XFLM_OK;
|
||||
IF_FileHdl * pDictFileHdl = NULL;
|
||||
FLMBOOL bFileOpen = FALSE;
|
||||
LFILE TempLFile;
|
||||
F_COLLECTION TempCollection;
|
||||
char * pszXMLBuffer = NULL;
|
||||
FLMUINT64 ui64FileSize;
|
||||
FLMUINT uiBytesRead;
|
||||
F_BufferIStream stream;
|
||||
|
||||
// This should never be called for a temporary database.
|
||||
|
||||
flmAssert( !m_pDatabase->m_bTempDb);
|
||||
|
||||
// Create the default data collection
|
||||
|
||||
if (RC_BAD(rc = m_pDatabase->lFileCreate( this, &TempCollection.lfInfo,
|
||||
&TempCollection, XFLM_DATA_COLLECTION, XFLM_LF_COLLECTION, FALSE, TRUE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Create the dictionary collection and indexes
|
||||
|
||||
if (RC_BAD(rc = m_pDatabase->lFileCreate( this, &TempCollection.lfInfo,
|
||||
&TempCollection,
|
||||
XFLM_DICT_COLLECTION, XFLM_LF_COLLECTION, FALSE, TRUE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = m_pDatabase->lFileCreate( this,
|
||||
&TempLFile, NULL, XFLM_DICT_NUMBER_INDEX, XFLM_LF_INDEX, FALSE, FALSE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = m_pDatabase->lFileCreate( this,
|
||||
&TempLFile, NULL, XFLM_DICT_NAME_INDEX, XFLM_LF_INDEX, FALSE, TRUE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Create the maintenance collection
|
||||
|
||||
if (RC_BAD(rc = m_pDatabase->lFileCreate( this, &TempCollection.lfInfo,
|
||||
&TempCollection,
|
||||
XFLM_MAINT_COLLECTION, XFLM_LF_COLLECTION, FALSE, TRUE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Create a new dictionary we can work with.
|
||||
|
||||
if (RC_BAD( rc = createNewDict()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If we have an XML buffer, there is no need to open the file.
|
||||
|
||||
if (!pszDictBuf && pszDictPath)
|
||||
{
|
||||
if (RC_BAD( rc = gv_pFileSystem->Open(
|
||||
pszDictPath, XFLM_IO_RDONLY, &pDictFileHdl)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bFileOpen = TRUE;
|
||||
|
||||
// Get the file size and allocate a buffer to hold the entire thing.
|
||||
|
||||
if (RC_BAD( rc = pDictFileHdl->Size( &ui64FileSize)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Add 1 to size so we can NULL terminate the string we read.
|
||||
|
||||
if (RC_BAD( rc = f_alloc( (FLMUINT)(ui64FileSize + 1), &pszXMLBuffer)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Read the entire file into the buffer
|
||||
|
||||
if (RC_BAD( rc = pDictFileHdl->Read( 0, (FLMUINT)ui64FileSize,
|
||||
pszXMLBuffer, &uiBytesRead)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
pszXMLBuffer [uiBytesRead] = 0;
|
||||
pszDictBuf = pszXMLBuffer;
|
||||
}
|
||||
if (!pszDictBuf || !(*pszDictBuf))
|
||||
{
|
||||
|
||||
// Neither a dictionary buffer or file were specified.
|
||||
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Parse through the buffer, extracting each XML document,
|
||||
// add to the dictionary and F_Dict object. The import method
|
||||
// reads stuff from the stream, parses it into XML documents,
|
||||
// and calls documentDone when the document is complete.
|
||||
// The documentDone method checks the dictionary syntax,
|
||||
// adds to the dictionary, etc.
|
||||
|
||||
if (RC_BAD( rc = stream.open( (FLMBYTE *)pszDictBuf, 0)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( import( &stream, XFLM_DICT_COLLECTION)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
m_pDict->getNameTable()->sortTags();
|
||||
|
||||
Exit:
|
||||
|
||||
if (bFileOpen)
|
||||
{
|
||||
pDictFileHdl->Close();
|
||||
}
|
||||
|
||||
if (pDictFileHdl)
|
||||
{
|
||||
pDictFileHdl->Release();
|
||||
}
|
||||
|
||||
if (pszXMLBuffer)
|
||||
{
|
||||
f_free( pszXMLBuffer);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
Reference in New Issue
Block a user