git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@494 0109f412-320b-0410-ab79-c3e0c5ffbbe6
17993 lines
337 KiB
C++
17993 lines
337 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: DOM node implementation
|
|
//
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 2003-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: fdom.cpp 3112 2006-01-19 13:12:40 -0700 (Thu, 19 Jan 2006) dsanders $
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
// Local constants
|
|
|
|
#define SEN_RESERVE_BYTES 5
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FINLINE RCODE F_Db::attrIsInIndexDef(
|
|
FLMUINT uiAttrNameId,
|
|
FLMBOOL * pbIsInIndexDef)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrElmInfo defInfo;
|
|
|
|
if( RC_BAD( rc = m_pDict->getAttribute( this, uiAttrNameId, &defInfo)))
|
|
{
|
|
return( rc);
|
|
}
|
|
|
|
*pbIsInIndexDef = defInfo.m_pFirstIcd ? TRUE : FALSE;
|
|
return( NE_XFLM_OK);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: This class converts a text stream of Unicode or UTF8 to an ASCII
|
|
text stream.
|
|
******************************************************************************/
|
|
class F_AsciiIStream : public IF_IStream
|
|
{
|
|
public:
|
|
|
|
F_AsciiIStream(
|
|
FLMBYTE * pucText,
|
|
FLMUINT uiNumBytesInBuffer,
|
|
eXFlmTextType eTextType)
|
|
{
|
|
m_pucText = pucText;
|
|
m_pucCurrPtr = pucText;
|
|
m_uiCurrChar = 0;
|
|
m_eTextType = eTextType;
|
|
|
|
if( uiNumBytesInBuffer)
|
|
{
|
|
m_pucEnd = &pucText[ uiNumBytesInBuffer];
|
|
}
|
|
else
|
|
{
|
|
m_pucEnd = NULL;
|
|
}
|
|
}
|
|
|
|
virtual ~F_AsciiIStream()
|
|
{
|
|
}
|
|
|
|
RCODE FLMAPI read(
|
|
void * pvBuffer,
|
|
FLMUINT uiBytesToRead,
|
|
FLMUINT * puiBytesRead);
|
|
|
|
FINLINE RCODE FLMAPI close( void)
|
|
{
|
|
return( NE_XFLM_OK);
|
|
}
|
|
|
|
private:
|
|
|
|
const FLMBYTE * m_pucText;
|
|
const FLMBYTE * m_pucCurrPtr;
|
|
const FLMBYTE * m_pucEnd;
|
|
FLMUINT m_uiCurrChar;
|
|
eXFlmTextType m_eTextType;
|
|
};
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
FLMINT FLMAPI F_BTreeIStream::Release( void)
|
|
{
|
|
FLMATOMIC refCnt = --m_refCnt;
|
|
|
|
if (m_refCnt == 0)
|
|
{
|
|
close();
|
|
if( gv_XFlmSysData.pNodePool)
|
|
{
|
|
m_refCnt = 1;
|
|
gv_XFlmSysData.pNodePool->insertBTreeIStream( this);
|
|
return( 0);
|
|
}
|
|
else
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
return( refCnt);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::canSetValue(
|
|
F_Db * pDb,
|
|
FLMUINT uiDataType)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Database * pDatabase = pDb->m_pDatabase;
|
|
IF_DOMNode * pNode = NULL;
|
|
eDomNodeType eNodeType = getNodeType();
|
|
|
|
if( eNodeType < ELEMENT_NODE || eNodeType > ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// Cannot set a value without a data type
|
|
|
|
if( uiDataType == XFLM_NODATA_TYPE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_DATA_TYPE);
|
|
goto Exit;
|
|
}
|
|
|
|
// If the node is read-only, don't allow it to be changed
|
|
|
|
if( getModeFlags() & FDOM_READ_ONLY)
|
|
{
|
|
rc = RC_SET( NE_XFLM_READ_ONLY);
|
|
goto Exit;
|
|
}
|
|
|
|
// If this is a comment or CDATA node, only allow text values
|
|
|
|
if (uiDataType != XFLM_TEXT_TYPE &&
|
|
(eNodeType == COMMENT_NODE || eNodeType == CDATA_SECTION_NODE))
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
// If the node is a data node and it has already been linked
|
|
// into the document, its data type cannot be changed.
|
|
|
|
if( getParentId() && eNodeType == DATA_NODE && uiDataType != getDataType())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
// Cannot allow a value to be set on this node if a pending input stream
|
|
// is still open.
|
|
|
|
if( pDatabase->m_pPendingInput &&
|
|
pDatabase->m_pPendingInput != m_pCachedNode)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FLMINT FLMAPI F_DOMNode::Release( void)
|
|
{
|
|
FLMINT iRefCnt = --m_refCnt;
|
|
|
|
if (iRefCnt == 0)
|
|
{
|
|
if( gv_XFlmSysData.pNodeCacheMgr)
|
|
{
|
|
m_refCnt = 1;
|
|
gv_XFlmSysData.pNodeCacheMgr->insertDOMNode( this);
|
|
return( 0);
|
|
}
|
|
else
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
return( iRefCnt);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::isChildTypeValid(
|
|
eDomNodeType eChildNodeType)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bTypeValid = FALSE;
|
|
|
|
if( !m_pCachedNode)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_INVALID_CHILD_TYPE);
|
|
goto Exit;
|
|
}
|
|
|
|
switch( getNodeType())
|
|
{
|
|
case ELEMENT_NODE:
|
|
{
|
|
if (eChildNodeType == ELEMENT_NODE ||
|
|
(eChildNodeType == DATA_NODE &&
|
|
getDataType() != XFLM_NODATA_TYPE && getDataLength() == 0) ||
|
|
eChildNodeType == COMMENT_NODE ||
|
|
eChildNodeType == PROCESSING_INSTRUCTION_NODE ||
|
|
eChildNodeType == CDATA_SECTION_NODE)
|
|
{
|
|
bTypeValid = TRUE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case DOCUMENT_NODE:
|
|
{
|
|
if (eChildNodeType == ELEMENT_NODE ||
|
|
eChildNodeType == PROCESSING_INSTRUCTION_NODE ||
|
|
eChildNodeType == COMMENT_NODE)
|
|
{
|
|
bTypeValid = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ATTRIBUTE_NODE:
|
|
case DATA_NODE:
|
|
case CDATA_SECTION_NODE:
|
|
case PROCESSING_INSTRUCTION_NODE:
|
|
case COMMENT_NODE:
|
|
{
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (!bTypeValid)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_INVALID_CHILD_TYPE);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::isDescendantOf(
|
|
F_Db * pDb,
|
|
F_DOMNode * pAncestor,
|
|
FLMBOOL * pbDescendant)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pParent = NULL;
|
|
FLMUINT64 ui64AncestorId;
|
|
FLMUINT64 ui64ThisParentId;
|
|
|
|
*pbDescendant = FALSE;
|
|
|
|
if( !m_pCachedNode)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ui64AncestorId = pAncestor->getNodeId();
|
|
ui64ThisParentId = getParentId();
|
|
|
|
if( ui64ThisParentId == ui64AncestorId)
|
|
{
|
|
*pbDescendant = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
if( !ui64ThisParentId ||
|
|
(ui64AncestorId != ui64ThisParentId &&
|
|
ui64ThisParentId == getDocumentId()) || !pAncestor->getFirstChildId())
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getParentNode( pDb, (IF_DOMNode **)&pParent)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
while( pParent)
|
|
{
|
|
if( pParent->getNodeId() == ui64AncestorId)
|
|
{
|
|
*pbDescendant = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pParent->getParentNode( pDb, (IF_DOMNode **)&pParent)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pParent)
|
|
{
|
|
pParent->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Notes: When an node is unlinked, its document or root node ID is not
|
|
changed. Once unlinked, the node can be deleted or re-linked
|
|
elsewhere within the same document.
|
|
This routine assumes that the caller has checked the cannot delete
|
|
bits and read-only bits if necessary.
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::unlinkNode(
|
|
F_Db * pDb,
|
|
FLMUINT uiFlags)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pTmpNode = NULL;
|
|
F_COLLECTION * pCollection = NULL;
|
|
FLMUINT64 ui64OldPrevSib = 0;
|
|
FLMUINT64 ui64OldNextSib = 0;
|
|
FLMBOOL bChangedThisHeader = FALSE;
|
|
eDomNodeType eNodeType;
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
// Unlink the node from its siblings and parent
|
|
|
|
if( (ui64OldPrevSib = getPrevSibId()) != 0)
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( getCollection(), getPrevSibId(),
|
|
&pTmpNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pTmpNode->setNextSibId( getNextSibId());
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
setPrevSibId( 0);
|
|
bChangedThisHeader = TRUE;
|
|
}
|
|
|
|
if( (ui64OldNextSib = getNextSibId()) != 0)
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( getCollection(), getNextSibId(),
|
|
&pTmpNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pTmpNode->setPrevSibId( ui64OldPrevSib);
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !bChangedThisHeader)
|
|
{
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
setNextSibId( 0);
|
|
bChangedThisHeader = TRUE;
|
|
}
|
|
|
|
if( getParentId())
|
|
{
|
|
FLMBOOL bChangedTmpHeader = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->getNode( getCollection(), getParentId(),
|
|
&pTmpNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND ||
|
|
rc == NE_XFLM_DOM_NODE_DELETED)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( eNodeType == ANNOTATION_NODE)
|
|
{
|
|
if (!bChangedTmpHeader)
|
|
{
|
|
if (RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bChangedTmpHeader = TRUE;
|
|
}
|
|
|
|
pTmpNode->setAnnotationId( 0);
|
|
}
|
|
else
|
|
{
|
|
// If the parent node is one whose child elements must all
|
|
// be unique, we must remove the node from the node list of the
|
|
// parent.
|
|
|
|
if( pTmpNode->getModeFlags() & FDOM_HAVE_CELM_LIST)
|
|
{
|
|
FLMUINT uiElmOffset;
|
|
|
|
if( !bChangedTmpHeader)
|
|
{
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bChangedTmpHeader = TRUE;
|
|
}
|
|
|
|
// Only element nodes should be child nodes of this parent.
|
|
|
|
flmAssert( eNodeType == ELEMENT_NODE);
|
|
|
|
if( !pTmpNode->findChildElm( getNameId(), &uiElmOffset))
|
|
{
|
|
// Child node should have been found.
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pTmpNode->removeChildElm( uiElmOffset)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// If this is a data node, we need to update the parent element's
|
|
// data node count
|
|
|
|
if( eNodeType == DATA_NODE)
|
|
{
|
|
if( !bChangedTmpHeader)
|
|
{
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bChangedTmpHeader = TRUE;
|
|
}
|
|
|
|
flmAssert( pTmpNode->getDataChildCount());
|
|
pTmpNode->setDataChildCount( pTmpNode->getDataChildCount() - 1);
|
|
}
|
|
|
|
if( !ui64OldPrevSib)
|
|
{
|
|
if( !bChangedTmpHeader)
|
|
{
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bChangedTmpHeader = TRUE;
|
|
}
|
|
|
|
flmAssert( pTmpNode->canHaveChildren());
|
|
pTmpNode->setFirstChildId( ui64OldNextSib);
|
|
}
|
|
|
|
if( !ui64OldNextSib)
|
|
{
|
|
if( !bChangedTmpHeader)
|
|
{
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bChangedTmpHeader = TRUE;
|
|
}
|
|
|
|
flmAssert( pTmpNode->canHaveChildren());
|
|
pTmpNode->setLastChildId( ui64OldPrevSib);
|
|
}
|
|
}
|
|
|
|
if( bChangedTmpHeader)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !bChangedThisHeader)
|
|
{
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
setParentId( 0);
|
|
bChangedThisHeader = TRUE;
|
|
}
|
|
|
|
// If this is a root node, the document list pointers may need
|
|
// to be updated
|
|
|
|
if( isRootNode())
|
|
{
|
|
if( eNodeType != DOCUMENT_NODE && eNodeType != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
// Get a pointer to the collection
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getCollection(
|
|
getCollection(), &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pCollection->ui64FirstDocId == getNodeId() ||
|
|
pCollection->ui64LastDocId == getNodeId())
|
|
{
|
|
// Clone the dictionary since the first/last document ID
|
|
// values of the collection will be changed
|
|
|
|
if( !(pDb->m_uiFlags & FDB_UPDATED_DICTIONARY))
|
|
{
|
|
if( RC_BAD( rc = pDb->dictClone()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Get a pointer to the new collection
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getCollection(
|
|
getCollection(), &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Change the first and/or last document IDs
|
|
|
|
if( pCollection->ui64FirstDocId == getNodeId())
|
|
{
|
|
pCollection->ui64FirstDocId = ui64OldNextSib;
|
|
pCollection->bNeedToUpdateNodes = TRUE;
|
|
}
|
|
|
|
if( pCollection->ui64LastDocId == getNodeId())
|
|
{
|
|
pCollection->ui64LastDocId = ui64OldPrevSib;
|
|
pCollection->bNeedToUpdateNodes = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If this is a data node, clear its name tag
|
|
|
|
if( eNodeType == DATA_NODE)
|
|
{
|
|
if( !bChangedThisHeader)
|
|
{
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
setNameId( 0);
|
|
bChangedThisHeader = TRUE;
|
|
}
|
|
|
|
if( bChangedThisHeader)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pTmpNode)
|
|
{
|
|
pTmpNode->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::addModeFlags(
|
|
F_Db * pDb,
|
|
FLMUINT uiFlags)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMUINT uiRflToken = 0;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Only need to set flags if they are not all currently set.
|
|
|
|
if( (getModeFlags() & uiFlags) != uiFlags)
|
|
{
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->addModeFlags(
|
|
pDb, m_uiAttrNameId, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pCachedNode->setFlags( uiFlags);
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( pRfl->logNodeFlagsUpdate(
|
|
pDb, getCollection(), m_pCachedNode->getNodeId(),
|
|
m_uiAttrNameId, uiFlags, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::removeModeFlags(
|
|
F_Db * pDb,
|
|
FLMUINT uiFlags)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMUINT uiRflToken = 0;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Only need to remove the flags if any of them are currently set.
|
|
|
|
if( getModeFlags() & uiFlags)
|
|
{
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->removeModeFlags(
|
|
pDb, m_uiAttrNameId, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pCachedNode->unsetFlags( uiFlags);
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( pRfl->logNodeFlagsUpdate(
|
|
pDb, getCollection(), m_pCachedNode->getNodeId(),
|
|
m_uiAttrNameId, uiFlags, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getData(
|
|
F_Db * pDb,
|
|
FLMBYTE * pucBuffer,
|
|
FLMUINT * puiLength)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
IF_PosIStream * pIStream = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_NodeBufferIStream bufferIStream;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If a NULL buffer is passed in, just return the
|
|
// data length
|
|
|
|
if( !pucBuffer)
|
|
{
|
|
rc = getDataLength( pDb, puiLength);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getIStream( pDb, &bufferIStream, &pIStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmReadStorageAsBinary( pIStream, pucBuffer,
|
|
*puiLength, 0, puiLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getDataLength(
|
|
IF_Db * ifpDb,
|
|
FLMUINT * puiLength)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
eDomNodeType eNodeType;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getDataLength(
|
|
m_uiAttrNameId, puiLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( (*puiLength = getDataLength()) == 0)
|
|
{
|
|
// If this is an element node, we will automatically search
|
|
// for the first data node (if any)
|
|
|
|
if( eNodeType == ELEMENT_NODE && getDataChildCount())
|
|
{
|
|
F_DOMNode * pNode = NULL;
|
|
|
|
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
*puiLength = pNode->getDataLength();
|
|
pNode->Release();
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::insertBefore(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode * ifpNewChild,
|
|
IF_DOMNode * ifpRefChild)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pFirstNewChild = NULL;
|
|
F_DOMNode * pLastNewChild = NULL;
|
|
F_DOMNode * pCurNewNode = NULL;
|
|
F_DOMNode * pNextSib = NULL;
|
|
F_DOMNode * pInsertBefore = NULL;
|
|
F_DOMNode * pTmpNode = NULL;
|
|
FLMBOOL bDescendant;
|
|
FLMBOOL bDone = FALSE;
|
|
FLMUINT64 ui64Tmp;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMBOOL bStartOfUpdate;
|
|
F_DOMNode * pDataElementNode = NULL;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
F_DOMNode * pNewChild = (F_DOMNode *)ifpNewChild;
|
|
F_DOMNode * pRefChild = (F_DOMNode *)ifpRefChild;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bUpdatedNode = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMUINT64 ui64RefChildId = 0;
|
|
eDomNodeType eThisNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eThisNodeType = getNodeType();
|
|
|
|
if( eThisNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pNewChild)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNewChild->syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pRefChild)
|
|
{
|
|
if( RC_BAD( rc = pRefChild->syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pRefChild->getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
ui64RefChildId = pRefChild->getNodeId();
|
|
}
|
|
|
|
if( pNewChild->getDatabase() != getDatabase() ||
|
|
pNewChild->getCollection() != getCollection())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNewChild->getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
// If this is a node whose children are all supposed to be unique,
|
|
// make sure that is the case, and find out where to insert the node.
|
|
|
|
if( getModeFlags() & FDOM_HAVE_CELM_LIST)
|
|
{
|
|
FLMUINT uiInsertPos;
|
|
|
|
// Only element child nodes are allowed.
|
|
|
|
if( pNewChild->getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_INVALID_CHILD_TYPE);
|
|
goto Exit;
|
|
}
|
|
|
|
// All of the element names must be unique.
|
|
|
|
if( m_pCachedNode->findChildElm( pNewChild->getNameId(),
|
|
&uiInsertPos))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_DUPLICATE_ELEMENT);
|
|
goto Exit;
|
|
}
|
|
|
|
// Element was not found, insert into the list of elements.
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bUpdatedNode = TRUE;
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->insertChildElm( uiInsertPos,
|
|
pNewChild->getNameId(),
|
|
pNewChild->getNodeId())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// If a non-NULL reference child was passed in,
|
|
// do some basic sanity checks
|
|
|
|
if( pRefChild)
|
|
{
|
|
if( pRefChild->getDatabase() != getDatabase() ||
|
|
pRefChild->getCollection() != getCollection())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNewChild->getNodeId() == pRefChild->getNodeId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pRefChild->getParentId() != getNodeId())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pFirstNewChild = pNewChild;
|
|
pFirstNewChild->AddRef();
|
|
|
|
pLastNewChild = pNewChild;
|
|
pLastNewChild->AddRef();
|
|
|
|
if( pRefChild)
|
|
{
|
|
pInsertBefore = pRefChild;
|
|
pInsertBefore->AddRef();
|
|
}
|
|
|
|
pCurNewNode = pFirstNewChild;
|
|
pCurNewNode->AddRef();
|
|
|
|
bStartOfUpdate = TRUE;
|
|
for( ;;)
|
|
{
|
|
// Make sure it is legal for the new child node to be
|
|
// linked to this node
|
|
|
|
if( RC_BAD( rc = isChildTypeValid( pCurNewNode->getNodeType())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If the node being inserted is not from the same document,
|
|
// we cannot perform the operation
|
|
|
|
if( pCurNewNode->getDocumentId() != getDocumentId())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_WRONG_DOCUMENT_ERR);
|
|
goto Exit;
|
|
}
|
|
|
|
// A document node can only have one element node and one document type
|
|
// node.
|
|
|
|
if( eThisNodeType == DOCUMENT_NODE)
|
|
{
|
|
if( pCurNewNode->getNodeType() == ELEMENT_NODE &&
|
|
getFirstChildId())
|
|
{
|
|
if( RC_BAD( rc = getChild( ifpDb, ELEMENT_NODE,
|
|
(IF_DOMNode **)&pTmpNode)))
|
|
{
|
|
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the next sibling node (if any) before we
|
|
// change the tree
|
|
|
|
if( pNextSib)
|
|
{
|
|
pNextSib->Release();
|
|
pNextSib = NULL;
|
|
}
|
|
|
|
if( RC_BAD( rc = pCurNewNode->getNextSibling( pDb,
|
|
(IF_DOMNode **)&pNextSib)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
bDone = TRUE;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( pDataElementNode)
|
|
{
|
|
pDataElementNode->Release();
|
|
pDataElementNode = NULL;
|
|
}
|
|
|
|
// Do indexing work before making changes
|
|
|
|
if( pCurNewNode->getNameId())
|
|
{
|
|
if( pCurNewNode->getNodeType() == DATA_NODE)
|
|
{
|
|
if( pCurNewNode->getParentId())
|
|
{
|
|
if( RC_BAD( rc = pCurNewNode->getParentNode( pDb,
|
|
(IF_DOMNode **)&pDataElementNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), pDataElementNode,
|
|
IX_DEL_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
|
|
if( !getFirstChildId())
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_DEL_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), pCurNewNode, IX_UNLINK_NODE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
}
|
|
|
|
// Remove pCurNewNode from the tree
|
|
|
|
if( pCurNewNode->getModeFlags() & (FDOM_CANNOT_DELETE | FDOM_READ_ONLY))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DELETE_NOT_ALLOWED);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pCurNewNode->unlinkNode( pDb, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pDataElementNode)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), pDataElementNode, IX_ADD_NODE_VALUE,
|
|
bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_DEL_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Make sure that "this" node is not a child of the node
|
|
// being inserted
|
|
|
|
if( RC_BAD( rc = isDescendantOf( pDb, pCurNewNode, &bDescendant)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bDescendant)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
|
|
goto Exit;
|
|
}
|
|
|
|
// If the node being inserted isn't from the same document,
|
|
// we cannot perform the operation
|
|
|
|
if( pCurNewNode->getDocumentId() != getDocumentId())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_WRONG_DOCUMENT_ERR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pCurNewNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pInsertBefore)
|
|
{
|
|
if( RC_BAD( rc = pInsertBefore->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Insert the new child before the ref child
|
|
|
|
if( !pInsertBefore->getPrevSibId())
|
|
{
|
|
if( !bUpdatedNode)
|
|
{
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bUpdatedNode = TRUE;
|
|
}
|
|
|
|
// Change the parent's first child pointer
|
|
|
|
setFirstChildId( pCurNewNode->getNodeId());
|
|
}
|
|
else
|
|
{
|
|
pCurNewNode->setPrevSibId( pInsertBefore->getPrevSibId());
|
|
|
|
// Get the prev sib and set its next sib value
|
|
|
|
if( RC_BAD( rc = pDb->getNode(
|
|
getCollection(), pInsertBefore->getPrevSibId(), &pTmpNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pTmpNode->setNextSibId( pCurNewNode->getNodeId());
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode,
|
|
FLM_UPD_INTERNAL_CHANGE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pTmpNode->Release();
|
|
pTmpNode = NULL;
|
|
}
|
|
|
|
pInsertBefore->setPrevSibId( pCurNewNode->getNodeId());
|
|
pCurNewNode->setNextSibId( pInsertBefore->getNodeId());
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pInsertBefore->m_pCachedNode,
|
|
FLM_UPD_INTERNAL_CHANGE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (ui64Tmp = getLastChildId()) != 0)
|
|
{
|
|
// Get the prev sib and set its next sib value
|
|
|
|
if( RC_BAD( rc = pDb->getNode(
|
|
getCollection(), getLastChildId(), &pTmpNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pTmpNode->setNextSibId( pCurNewNode->getNodeId());
|
|
pCurNewNode->setPrevSibId( getLastChildId());
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode,
|
|
FLM_UPD_INTERNAL_CHANGE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pTmpNode->Release();
|
|
pTmpNode = NULL;
|
|
}
|
|
|
|
pCurNewNode->setPrevSibId( getLastChildId());
|
|
|
|
if( !bUpdatedNode)
|
|
{
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bUpdatedNode = TRUE;
|
|
}
|
|
|
|
setLastChildId( pCurNewNode->getNodeId());
|
|
|
|
if( !ui64Tmp)
|
|
{
|
|
setFirstChildId( pCurNewNode->getNodeId());
|
|
}
|
|
}
|
|
|
|
// Need to increment the data child node count
|
|
|
|
if( pCurNewNode->getNodeType() == DATA_NODE &&
|
|
eThisNodeType == ELEMENT_NODE)
|
|
{
|
|
setDataChildCount( getDataChildCount() + 1);
|
|
bUpdatedNode = TRUE;
|
|
}
|
|
|
|
if( bUpdatedNode)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode,
|
|
FLM_UPD_INTERNAL_CHANGE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Reset to FALSE for next time around in loop.
|
|
|
|
bUpdatedNode = FALSE;
|
|
}
|
|
|
|
pCurNewNode->setParentId( getNodeId());
|
|
|
|
// Need to set the naming tag and data type of the node.
|
|
|
|
if( pCurNewNode->getNodeType() == DATA_NODE &&
|
|
eThisNodeType == ELEMENT_NODE)
|
|
{
|
|
if( pCurNewNode->getDataType() == XFLM_NODATA_TYPE)
|
|
{
|
|
pCurNewNode->setDataType( getDataType());
|
|
}
|
|
else if( getDataType() != pCurNewNode->getDataType())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
pCurNewNode->setNameId( getNameId());
|
|
}
|
|
|
|
// An additional restriction on unique child elements is that they
|
|
// must have a node ID greater than the parent element. This allows
|
|
// them to be stored using a very compact representation.
|
|
|
|
if( getModeFlags() & FDOM_HAVE_CELM_LIST)
|
|
{
|
|
if( pCurNewNode->getNodeId() < getNodeId())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_INVALID_CHILD_ELM_NODE_ID);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pCurNewNode->m_pCachedNode,
|
|
FLM_UPD_INTERNAL_CHANGE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pCurNewNode->getNodeId() == pLastNewChild->getNodeId())
|
|
{
|
|
bDone = TRUE;
|
|
}
|
|
|
|
// Do post-link indexing work
|
|
|
|
if( pCurNewNode->getNameId())
|
|
{
|
|
if( pCurNewNode->getNodeType() == DATA_NODE)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), pCurNewNode, IX_LINK_NODE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
|
|
pCurNewNode->Release();
|
|
pCurNewNode = pNextSib;
|
|
pNextSib = NULL;
|
|
|
|
if( bDone)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logInsertBefore(
|
|
pDb, getCollection(), getNodeId(), pNewChild->getNodeId(),
|
|
ui64RefChildId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
// Release any nodes we are still holding
|
|
|
|
if( pFirstNewChild)
|
|
{
|
|
pFirstNewChild->Release();
|
|
}
|
|
|
|
if( pLastNewChild)
|
|
{
|
|
pLastNewChild->Release();
|
|
}
|
|
|
|
if( pCurNewNode)
|
|
{
|
|
pCurNewNode->Release();
|
|
}
|
|
|
|
if( pDataElementNode)
|
|
{
|
|
pDataElementNode->Release();
|
|
}
|
|
|
|
if( pNextSib)
|
|
{
|
|
pNextSib->Release();
|
|
}
|
|
|
|
if( pInsertBefore)
|
|
{
|
|
pInsertBefore->Release();
|
|
}
|
|
|
|
if( pTmpNode)
|
|
{
|
|
pTmpNode->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::setNumber64(
|
|
IF_Db * ifpDb,
|
|
FLMINT64 i64Value,
|
|
FLMUINT64 ui64Value,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bNeg = FALSE;
|
|
F_Db * pDb = (F_Db*)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
IF_DOMNode * pNode = NULL;
|
|
FLMUINT uiCollection;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMUINT uiNodeDataType;
|
|
FLMUINT uiValLen;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bIsIndexed = TRUE;
|
|
FLMBOOL bStartOfUpdate = TRUE;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = canSetValue( pDb, XFLM_NUMBER_TYPE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Grab some information about the node
|
|
|
|
uiCollection = getCollection();
|
|
eNodeType = getNodeType();
|
|
|
|
// Special case for element nodes
|
|
|
|
if( eNodeType == ELEMENT_NODE && getDataChildCount())
|
|
{
|
|
if( RC_BAD( rc = getChild( pDb, DATA_NODE, &pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
rc = ((F_DOMNode *)pNode)->setNumber64( pDb, i64Value,
|
|
ui64Value, uiEncDefId);
|
|
goto Exit;
|
|
}
|
|
|
|
// If the number is less than zero, invert the sign
|
|
|
|
if( i64Value < 0)
|
|
{
|
|
bNeg = TRUE;
|
|
ui64Value = (FLMUINT64)(-i64Value);
|
|
}
|
|
else if( i64Value)
|
|
{
|
|
ui64Value = (FLMUINT64)i64Value;
|
|
}
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = makeWriteCopy( (F_Db *)ifpDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
|
|
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->setNumber64( pDb,
|
|
m_uiAttrNameId, ui64Value, bNeg, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
uiCollection, this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the value to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
|
|
m_pCachedNode, m_uiAttrNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
// Generate the storage value
|
|
|
|
uiNodeDataType = getDataType();
|
|
|
|
if( uiNodeDataType == XFLM_NUMBER_TYPE ||
|
|
uiNodeDataType == XFLM_NODATA_TYPE)
|
|
{
|
|
if( bNeg)
|
|
{
|
|
if( (getModeFlags() & FDOM_SIGNED_QUICK_VAL) &&
|
|
i64Value == getQuickINT64())
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( (getModeFlags() & FDOM_UNSIGNED_QUICK_VAL) &&
|
|
ui64Value == getQuickUINT64())
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( getNameId())
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
|
|
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bIsIndexed = FALSE;
|
|
}
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( (F_Db *)ifpDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getDataBufSize() < FLM_MAX_NUM_BUF_SIZE)
|
|
{
|
|
if( RC_BAD( rc = resizeDataBuffer( FLM_MAX_NUM_BUF_SIZE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
uiValLen = FLM_MAX_NUM_BUF_SIZE;
|
|
if( RC_BAD( rc = flmNumber64ToStorage( ui64Value,
|
|
&uiValLen, getDataPtr(), bNeg, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiNodeDataType == XFLM_NODATA_TYPE)
|
|
{
|
|
uiNodeDataType = XFLM_NUMBER_TYPE;
|
|
setDataType( uiNodeDataType);
|
|
}
|
|
}
|
|
else if( uiNodeDataType == XFLM_TEXT_TYPE)
|
|
{
|
|
FLMBYTE ucNumBuf[ 64];
|
|
FLMBYTE * pucSen;
|
|
FLMUINT uiSenLen;
|
|
|
|
if( !bNeg)
|
|
{
|
|
f_ui64toa( ui64Value, (char *)&ucNumBuf[ 1]);
|
|
}
|
|
else
|
|
{
|
|
f_i64toa( i64Value, (char *)&ucNumBuf[ 1]);
|
|
}
|
|
|
|
uiValLen = f_strlen( (const char *)ucNumBuf);
|
|
pucSen = &ucNumBuf[ 0];
|
|
uiSenLen = f_encodeSEN( uiValLen, &pucSen, (FLMUINT)0);
|
|
flmAssert( uiSenLen == 1);
|
|
uiValLen += uiSenLen + 1;
|
|
|
|
// If the value isn't being changed, there is no need to continue
|
|
|
|
if( getDataLength() == uiValLen &&
|
|
f_memcmp( getDataPtr(), ucNumBuf, uiValLen) == 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( getNameId())
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
|
|
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bIsIndexed = FALSE;
|
|
}
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( (F_Db *)ifpDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Allocate or re-allocate the buffer
|
|
|
|
if( calcDataBufSize( uiValLen) > getDataBufSize())
|
|
{
|
|
if( RC_BAD( rc = resizeDataBuffer( uiValLen, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( uiValLen)
|
|
{
|
|
f_memcpy( getDataPtr(), ucNumBuf, uiValLen);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_DATA_TYPE);
|
|
goto Exit;
|
|
}
|
|
|
|
setEncDefId( uiEncDefId);
|
|
setDataLength( uiValLen);
|
|
|
|
// Clear the "on disk" flag (if set), as well as the quick nums
|
|
|
|
unsetFlags( FDOM_VALUE_ON_DISK |
|
|
FDOM_FIXED_SIZE_HEADER |
|
|
FDOM_UNSIGNED_QUICK_VAL |
|
|
FDOM_SIGNED_QUICK_VAL);
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
|
|
this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
|
|
if( !bNeg)
|
|
{
|
|
setUINT64( ui64Value);
|
|
}
|
|
else
|
|
{
|
|
setINT64( i64Value);
|
|
}
|
|
|
|
// Log the value to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( !uiEncDefId)
|
|
{
|
|
if( RC_BAD( rc = pRfl->logNodeSetNumberValue( pDb,
|
|
uiCollection, getNodeId(), ui64Value, bNeg)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pRfl->logEncryptedNodeUpdate( pDb, m_pCachedNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::setStorageValue(
|
|
F_Db * pDb,
|
|
void * pvValue,
|
|
FLMUINT uiValueLen,
|
|
FLMUINT uiEncDefId,
|
|
FLMBOOL bLast)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiCollection;
|
|
eDomNodeType eNodeType;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bIsIndexed = TRUE;
|
|
F_Database * pDatabase = pDb->m_pDatabase;
|
|
FLMBOOL bFirst = pDatabase->m_pPendingInput ? FALSE : TRUE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getDataType() == XFLM_UNKNOWN_TYPE || (bStartedTrans && !bLast))
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
uiCollection = getCollection();
|
|
eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ELEMENT_NODE ||
|
|
eNodeType == DATA_NODE)
|
|
{
|
|
if( !getNameId())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( bFirst)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
|
|
this, IX_DEL_NODE_VALUE, TRUE, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( eNodeType == ELEMENT_NODE ||
|
|
eNodeType == DATA_NODE ||
|
|
eNodeType == COMMENT_NODE)
|
|
{
|
|
FLMUINT uiBytesToCopy;
|
|
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
|
|
|
|
if( bFirst)
|
|
{
|
|
setEncDefId( uiEncDefId);
|
|
}
|
|
|
|
if( bFirst && bLast)
|
|
{
|
|
if( calcDataBufSize( uiValueLen) != getDataBufSize())
|
|
{
|
|
if( RC_BAD( rc = resizeDataBuffer( uiValueLen, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
setDataLength( uiValueLen);
|
|
|
|
if( uiValueLen)
|
|
{
|
|
f_memcpy( getDataPtr(), pvValue, uiValueLen);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( bFirst)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->openPendingInput( pDb,
|
|
getDataType())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
while( uiValueLen)
|
|
{
|
|
uiBytesToCopy = pDatabase->m_uiUpdBufferSize -
|
|
pDatabase->m_uiUpdByteCount;
|
|
|
|
uiBytesToCopy = uiBytesToCopy > uiValueLen
|
|
? uiValueLen
|
|
: uiBytesToCopy;
|
|
|
|
if( !uiBytesToCopy)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->flushPendingInput( pDb, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
f_memcpy( &pDatabase->m_pucUpdBuffer[ pDatabase->m_uiUpdByteCount],
|
|
pucValue, uiBytesToCopy);
|
|
pucValue += uiBytesToCopy;
|
|
uiValueLen -= uiBytesToCopy;
|
|
pDatabase->m_uiUpdByteCount += uiBytesToCopy;
|
|
}
|
|
|
|
if( bLast)
|
|
{
|
|
if( pDatabase->m_bUpdFirstBuf)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->flushPendingInput( pDb, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->flushPendingInput( pDb, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pDatabase->endPendingInput();
|
|
}
|
|
}
|
|
}
|
|
else if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
if( !bLast)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->setStorageValue(
|
|
pDb, m_uiAttrNameId, pvValue, uiValueLen, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( bLast)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
|
|
this, IX_ADD_NODE_VALUE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
if( bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
pDatabase->endPendingInput();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::openPendingInput(
|
|
F_Db * pDb,
|
|
FLMUINT uiNewDataType)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Database * pDatabase = pDb->m_pDatabase;
|
|
eDomNodeType eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// Set up the database to point to this node. Only one node
|
|
// is allowed to stream data into the B-Tree at a time.
|
|
|
|
if( RC_BAD( rc = pDatabase->startPendingInput( uiNewDataType, this)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If the naming tag has already been set, make sure the
|
|
// new data type is compatible with the defined type for
|
|
// the tag.
|
|
|
|
if( getNameId())
|
|
{
|
|
switch( eNodeType)
|
|
{
|
|
case ELEMENT_NODE:
|
|
case DATA_NODE:
|
|
{
|
|
F_AttrElmInfo elmInfo;
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getElement(
|
|
pDb, m_nodeInfo.uiNameId, &elmInfo)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( elmInfo.getDataType() != uiNewDataType)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ANNOTATION_NODE:
|
|
{
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Better be the latest version for update.
|
|
|
|
flmAssert( m_ui64LowTransId == pDb->m_ui64CurrTransID);
|
|
|
|
m_nodeInfo.uiDataLength = 0;
|
|
m_nodeInfo.uiDataType = uiNewDataType;
|
|
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
|
|
setFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
|
|
|
|
flmAssert( !pDatabase->m_uiUpdByteCount);
|
|
flmAssert( !pDatabase->m_uiUpdCharCount);
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDatabase->endPendingInput();
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::flushPendingInput(
|
|
F_Db * pDb,
|
|
FLMBOOL bLast)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_COLLECTION * pCollection = NULL;
|
|
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
|
|
FLMBYTE ucHeader[ MAX_DOM_HEADER_SIZE + 16];
|
|
FLMUINT uiKeyLen;
|
|
FLMUINT uiHeaderStorageSize;
|
|
F_Database * pDatabase = pDb->m_pDatabase;
|
|
FLMUINT uiOutputLength;
|
|
FLMUINT uiLeftoverLength;
|
|
|
|
uiKeyLen = sizeof( ucKey);
|
|
if( RC_BAD( rc = flmNumber64ToStorage( m_nodeInfo.ui64NodeId,
|
|
&uiKeyLen, ucKey, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Open the B-Tree
|
|
|
|
if( !pDatabase->m_pPendingBTree)
|
|
{
|
|
if( !pDatabase->m_bUpdFirstBuf)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree(
|
|
&pDatabase->m_pPendingBTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getCollection(
|
|
m_nodeInfo.uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btOpen(
|
|
pDb, &pCollection->lfInfo, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Better be the latest version for update.
|
|
|
|
flmAssert( m_ui64LowTransId == pDb->m_ui64CurrTransID);
|
|
uiOutputLength = pDatabase->m_uiUpdByteCount;
|
|
uiLeftoverLength = 0;
|
|
|
|
// Output the node header
|
|
|
|
if( pDatabase->m_bUpdFirstBuf)
|
|
{
|
|
FLMUINT uiIVLen = 0;
|
|
|
|
// This routine is designed to handle multi-block data streams.
|
|
// It shouldn't be called if everything fits within the a single
|
|
// update buffer.
|
|
|
|
flmAssert( !bLast);
|
|
|
|
// There shouldn't be any attributes at this point, because
|
|
// this shouldn't be an element node
|
|
|
|
flmAssert( !hasAttributes());
|
|
flmAssert( m_nodeInfo.eNodeType != ELEMENT_NODE);
|
|
|
|
// Build the node header
|
|
|
|
if( RC_BAD( rc = headerToBuf( TRUE, ucHeader,
|
|
&uiHeaderStorageSize, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getEncDefId())
|
|
{
|
|
F_ENCDEF * pEncDef;
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getEncDef( getEncDefId(), &pEncDef)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiIVLen = pEncDef->pCcs->getIVLen();
|
|
flmAssert( uiIVLen == 8 || uiIVLen == 16);
|
|
|
|
if( RC_BAD( rc = pEncDef->pCcs->generateIV( uiIVLen, pDatabase->m_ucIV)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_memcpy( &ucHeader[ uiHeaderStorageSize], pDatabase->m_ucIV, uiIVLen);
|
|
}
|
|
|
|
// Output the header
|
|
|
|
if( nodeIsNew())
|
|
{
|
|
// If this is a new entry, we need to insert it into the
|
|
// b-tree.
|
|
|
|
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btInsertEntry(
|
|
ucKey, uiKeyLen,
|
|
ucHeader, uiHeaderStorageSize + uiIVLen, TRUE, FALSE,
|
|
&m_ui32BlkAddr, &m_uiOffsetIndex)))
|
|
{
|
|
if( rc == NE_XFLM_NOT_UNIQUE)
|
|
{
|
|
rc = RC_SET( NE_XFLM_EXISTS);
|
|
}
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btReplaceEntry(
|
|
ucKey, uiKeyLen,
|
|
ucHeader, uiHeaderStorageSize + uiIVLen, TRUE, FALSE, TRUE,
|
|
&m_ui32BlkAddr, &m_uiOffsetIndex)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pDatabase->m_bUpdFirstBuf = FALSE;
|
|
}
|
|
|
|
// Output the data buffer
|
|
|
|
if( pDatabase->m_uiUpdByteCount || bLast)
|
|
{
|
|
// Encrypt the buffer if this node is encrypted. If encrypted,
|
|
// uiOutputLength will hold the length of the encrypted data.
|
|
// If not encrypted, it will hold the length of the non-encrypted data,
|
|
// i.e. pDatabase->m_uiUpdByteCount. the encrypted data will be returned
|
|
// in the input buffer.
|
|
|
|
if( getEncDefId())
|
|
{
|
|
// If this is not the last buffer, only encrypt to the nearest
|
|
// FLM_ENCRYPT_CHUNK_SIZE byte boundary. Move whatever we don't
|
|
// encrypt down to the beginning of the buffer after writing the
|
|
// encrypted part out to the B-tree (see below). This is necessary
|
|
// because the decryption algorithm assumes that all of the
|
|
// encrypted data is in FLM_ENRYPT_CHUNK_SIZE byte chunks - except
|
|
// for the last chunk, which may be encrypted to the nearest 16 byte
|
|
// boundary.
|
|
|
|
if( !bLast && (uiOutputLength & (FLM_ENCRYPT_CHUNK_SIZE - 1)))
|
|
{
|
|
uiLeftoverLength = uiOutputLength & (FLM_ENCRYPT_CHUNK_SIZE - 1);
|
|
uiOutputLength -= uiLeftoverLength;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->encryptData( getEncDefId(), pDatabase->m_ucIV,
|
|
pDatabase->m_pucUpdBuffer, pDatabase->m_uiUpdBufferSize,
|
|
uiOutputLength, &uiOutputLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( nodeIsNew())
|
|
{
|
|
// If this is a new entry, we need to continue calling the
|
|
// insert method to stream its data into the b-tree
|
|
|
|
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btInsertEntry(
|
|
ucKey, uiKeyLen,
|
|
pDatabase->m_pucUpdBuffer, uiOutputLength,
|
|
FALSE, bLast,
|
|
&m_ui32BlkAddr, &m_uiOffsetIndex)))
|
|
{
|
|
if( rc == NE_XFLM_NOT_UNIQUE)
|
|
{
|
|
rc = RC_SET( NE_XFLM_EXISTS);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btReplaceEntry(
|
|
ucKey, uiKeyLen,
|
|
pDatabase->m_pucUpdBuffer, uiOutputLength,
|
|
FALSE, bLast, TRUE,
|
|
&m_ui32BlkAddr, &m_uiOffsetIndex)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_nodeInfo.uiDataLength += uiOutputLength;
|
|
if( (pDatabase->m_uiUpdByteCount = uiLeftoverLength) != 0)
|
|
{
|
|
f_memmove( pDatabase->m_pucUpdBuffer,
|
|
pDatabase->m_pucUpdBuffer + uiOutputLength, uiLeftoverLength);
|
|
}
|
|
|
|
if( bLast)
|
|
{
|
|
// Clear the dirty flag and the new flag.
|
|
|
|
unsetNodeDirtyAndNew( pDb);
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::setMetaValue(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 ui64Value)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db*)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
// Only allow meta values on element nodes.
|
|
|
|
if( eNodeType != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// If the value isn't changing, don't do anything
|
|
|
|
if( ui64Value == getMetaValue())
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Make sure the node can be updated
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set the value
|
|
|
|
setMetaValue( ui64Value);
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode(
|
|
m_pCachedNode, FLM_UPD_INTERNAL_CHANGE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the value to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeSetMetaValue( pDb,
|
|
getCollection(), getNodeId(), ui64Value)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getMetaValue(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 * pui64Value)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db*)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64Value = getMetaValue();
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::isDataLocalToNode(
|
|
IF_Db * ifpDb,
|
|
FLMBOOL * pbDataIsLocal)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db*)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
*pbDataIsLocal = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pbDataIsLocal = getDataLength() ? TRUE : FALSE;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Read from a text stream, outputting ASCII. If we encounter a
|
|
character that cannot be output as ASCII, we will return an error.
|
|
******************************************************************************/
|
|
RCODE F_AsciiIStream::read(
|
|
void * pvBuffer,
|
|
FLMUINT uiBytesToRead,
|
|
FLMUINT * puiBytesRead)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
|
|
FLMUNICODE uzChar;
|
|
|
|
*puiBytesRead = 0;
|
|
while( *puiBytesRead < uiBytesToRead)
|
|
{
|
|
if( m_eTextType == XFLM_UNICODE_TEXT)
|
|
{
|
|
if( (m_pucEnd && ((FLMUINT)(m_pucEnd - m_pucCurrPtr) <
|
|
sizeof( FLMUNICODE))) ||
|
|
(uzChar = *((FLMUNICODE *)m_pucCurrPtr)) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( uzChar > 127)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
|
|
*pucBuffer++ = (FLMBYTE)uzChar;
|
|
m_pucCurrPtr += sizeof( FLMUNICODE);
|
|
}
|
|
else // UTF8
|
|
{
|
|
if( RC_BAD( rc = f_getCharFromUTF8Buf(
|
|
&m_pucCurrPtr, m_pucEnd, &uzChar)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !uzChar)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( uzChar > 127)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
|
|
*pucBuffer++ = (FLMBYTE)uzChar;
|
|
}
|
|
|
|
m_uiCurrChar++;
|
|
(*puiBytesRead)++;
|
|
}
|
|
|
|
if( *puiBytesRead < uiBytesToRead)
|
|
{
|
|
rc = RC_SET( NE_XFLM_EOF_HIT);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: This class converts a storage text stream to an ASCII
|
|
text stream.
|
|
******************************************************************************/
|
|
class F_AsciiStorageStream : public IF_IStream
|
|
{
|
|
public:
|
|
|
|
F_AsciiStorageStream()
|
|
{
|
|
m_pIStream = NULL;
|
|
}
|
|
|
|
~F_AsciiStorageStream()
|
|
{
|
|
close();
|
|
}
|
|
|
|
RCODE FLMAPI read(
|
|
void * pvBuffer,
|
|
FLMUINT uiBytesToRead,
|
|
FLMUINT * puiBytesRead);
|
|
|
|
FINLINE RCODE FLMAPI close( void)
|
|
{
|
|
if( m_pIStream)
|
|
{
|
|
m_pIStream->Release();
|
|
m_pIStream = NULL;
|
|
}
|
|
|
|
return( NE_XFLM_OK);
|
|
}
|
|
|
|
RCODE open(
|
|
IF_IStream * pIStream);
|
|
|
|
private:
|
|
|
|
IF_IStream * m_pIStream;
|
|
};
|
|
|
|
/*****************************************************************************
|
|
Desc: Open an Ascii storage stream.
|
|
******************************************************************************/
|
|
RCODE F_AsciiStorageStream::open(
|
|
IF_IStream * pIStream)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE ucSENBuf [16];
|
|
FLMUINT uiLen;
|
|
FLMUINT uiSENLen;
|
|
|
|
close();
|
|
m_pIStream = pIStream;
|
|
m_pIStream->AddRef();
|
|
|
|
// Skip over the SEN
|
|
|
|
uiLen = 1;
|
|
if( RC_BAD( rc = m_pIStream->read( (char *)&ucSENBuf [0], uiLen, &uiLen)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( (uiSENLen = f_getSENLength( ucSENBuf[ 0])) > 1)
|
|
{
|
|
uiLen = uiSENLen - 1;
|
|
if( RC_BAD( rc = m_pIStream->read(
|
|
(char *)&ucSENBuf [1], uiLen, &uiLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// We are now positioned to read UTF8
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
close();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Read from a storage text stream, outputting ASCII. If we encounter a
|
|
character that cannot be output as ASCII, we will return an error.
|
|
******************************************************************************/
|
|
RCODE F_AsciiStorageStream::read(
|
|
void * pvBuffer,
|
|
FLMUINT uiBytesToRead,
|
|
FLMUINT * puiBytesRead)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUNICODE uzChar;
|
|
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
|
|
FLMUINT uiBytesRead = 0;
|
|
|
|
// Better have a stream that has been positioned by a call to open().
|
|
|
|
flmAssert( m_pIStream);
|
|
|
|
while( uiBytesRead < uiBytesToRead)
|
|
{
|
|
if( RC_BAD( rc = f_readUTF8CharAsUnicode( m_pIStream, &uzChar)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( uzChar <= 127)
|
|
{
|
|
*pucBuffer++ = (FLMBYTE)uzChar;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
|
|
uiBytesRead++;
|
|
}
|
|
|
|
if( uiBytesRead < uiBytesToRead)
|
|
{
|
|
rc = RC_SET( NE_XFLM_EOF_HIT);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( puiBytesRead)
|
|
{
|
|
*puiBytesRead = uiBytesRead;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: This class converts a binary stream to an ASCII text storage
|
|
stream.
|
|
******************************************************************************/
|
|
class F_BinaryToTextStream : public IF_IStream
|
|
{
|
|
public:
|
|
|
|
F_BinaryToTextStream()
|
|
{
|
|
m_pEncoderStream = NULL;
|
|
}
|
|
|
|
~F_BinaryToTextStream()
|
|
{
|
|
close();
|
|
}
|
|
|
|
RCODE FLMAPI read(
|
|
void * pvBuffer,
|
|
FLMUINT uiBytesToRead,
|
|
FLMUINT * puiBytesRead);
|
|
|
|
FINLINE RCODE FLMAPI close( void)
|
|
{
|
|
if( m_pEncoderStream)
|
|
{
|
|
m_pEncoderStream->Release();
|
|
m_pEncoderStream = NULL;
|
|
}
|
|
|
|
return( NE_XFLM_OK);
|
|
}
|
|
|
|
RCODE open(
|
|
IF_IStream * pIStream,
|
|
FLMUINT uiDataLen,
|
|
FLMUINT * puiTextLength);
|
|
|
|
private:
|
|
|
|
FLMBYTE m_ucSENBuf [16];
|
|
FLMUINT m_uiSENLen;
|
|
FLMUINT m_uiCurrOffset;
|
|
IF_IStream * m_pEncoderStream;
|
|
};
|
|
|
|
/*****************************************************************************
|
|
Desc: Open a binary-to-text stream.
|
|
******************************************************************************/
|
|
RCODE F_BinaryToTextStream::open(
|
|
IF_IStream * pIStream,
|
|
FLMUINT uiDataLen,
|
|
FLMUINT * puiTextLength)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE * pucSen;
|
|
FLMUINT uiOutputLen;
|
|
|
|
close();
|
|
|
|
// Set up the SEN buffer. Calculate length to be 4 bytes for every 3
|
|
// binary bytes.
|
|
|
|
uiOutputLen = (uiDataLen / 3) * 4;
|
|
|
|
// If number of bytes is not an exact multiple of 3, we will need 4
|
|
// more bytes.
|
|
|
|
if( uiDataLen % 3)
|
|
{
|
|
uiOutputLen += 4;
|
|
}
|
|
|
|
pucSen = &m_ucSENBuf [0];
|
|
m_uiSENLen = f_encodeSEN( (FLMUINT64)uiOutputLen, &pucSen, (FLMUINT)0);
|
|
m_uiCurrOffset = 0;
|
|
|
|
// Need to include the data length, SEN length, and the terminating null
|
|
// character.
|
|
|
|
*puiTextLength = uiOutputLen + m_uiSENLen + 1;
|
|
|
|
// Set up the encoder stream
|
|
|
|
if( RC_BAD( rc = FlmOpenBase64EncoderIStream( pIStream,
|
|
FALSE, &m_pEncoderStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
close();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Read from a binary stream, outputting base 64 encoded ASCII.
|
|
******************************************************************************/
|
|
RCODE F_BinaryToTextStream::read(
|
|
void * pvBuffer,
|
|
FLMUINT uiBytesToRead,
|
|
FLMUINT * puiBytesRead)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
|
|
FLMUINT uiBytesRead;
|
|
|
|
// Better have a stream that has been positioned by a call to open().
|
|
|
|
flmAssert( m_pEncoderStream);
|
|
*puiBytesRead = 0;
|
|
|
|
if( m_uiCurrOffset < m_uiSENLen)
|
|
{
|
|
if( uiBytesToRead >= m_uiSENLen - m_uiCurrOffset)
|
|
{
|
|
f_memcpy( pucBuffer, &m_ucSENBuf [m_uiCurrOffset],
|
|
m_uiSENLen - m_uiCurrOffset);
|
|
(*puiBytesRead) += (m_uiSENLen - m_uiCurrOffset);
|
|
pucBuffer += (m_uiSENLen - m_uiCurrOffset);
|
|
m_uiCurrOffset = m_uiSENLen;
|
|
}
|
|
else
|
|
{
|
|
f_memcpy( pucBuffer, &m_ucSENBuf [m_uiCurrOffset],
|
|
uiBytesToRead);
|
|
(*puiBytesRead) += uiBytesToRead;
|
|
m_uiCurrOffset += uiBytesToRead;
|
|
pucBuffer += uiBytesToRead;
|
|
}
|
|
}
|
|
|
|
// If we didn't get everything from the SEN buffer, read from the
|
|
// decoding stream.
|
|
|
|
if( *puiBytesRead < uiBytesToRead)
|
|
{
|
|
if( RC_BAD( rc = m_pEncoderStream->read( pucBuffer,
|
|
uiBytesToRead - *puiBytesRead, &uiBytesRead)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
(*puiBytesRead) += uiBytesRead;
|
|
}
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
(*puiBytesRead) += uiBytesRead;
|
|
}
|
|
}
|
|
|
|
if( *puiBytesRead < uiBytesToRead)
|
|
{
|
|
rc = RC_SET( NE_XFLM_EOF_HIT);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Store text as a number.
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::storeTextAsNumber(
|
|
F_Db * pDb,
|
|
void * pvValue,
|
|
FLMUINT uiNumBytesInBuffer,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE ucChar;
|
|
FLMUINT uiIncrAmount = 0;
|
|
FLMBOOL bNeg = FALSE;
|
|
FLMBOOL bHex = FALSE;
|
|
FLMUINT64 ui64Num = 0;
|
|
FLMUINT uiBytesRead;
|
|
FLMBOOL bFirstChar = TRUE;
|
|
F_AsciiIStream asciiStream( (FLMBYTE *)pvValue, uiNumBytesInBuffer, XFLM_UTF8_TEXT);
|
|
|
|
// Convert the text to a number.
|
|
|
|
for (;;)
|
|
{
|
|
if( RC_BAD( rc = asciiStream.read( &ucChar, 1, &uiBytesRead)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
break;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
// See if we can convert to a number.
|
|
|
|
if( ucChar >= ASCII_ZERO && ucChar <= ASCII_NINE)
|
|
{
|
|
uiIncrAmount = (FLMUINT)(ucChar - '0');
|
|
}
|
|
else if( ucChar >= ASCII_UPPER_A && ucChar <= ASCII_UPPER_F)
|
|
{
|
|
if( bHex)
|
|
{
|
|
uiIncrAmount = (FLMUINT)(ucChar - ASCII_UPPER_A + 10);
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( ucChar >= ASCII_LOWER_A && ucChar <= ASCII_LOWER_F)
|
|
{
|
|
if( bHex)
|
|
{
|
|
uiIncrAmount = (FLMUINT)(ucChar - ASCII_LOWER_A + 10);
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( ucChar == ASCII_LOWER_X || ucChar == ASCII_UPPER_X)
|
|
{
|
|
if( !ui64Num && !bHex)
|
|
{
|
|
bHex = TRUE;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( ucChar == ASCII_DASH && bFirstChar)
|
|
{
|
|
bNeg = TRUE;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !bHex)
|
|
{
|
|
if( ui64Num > (~(FLMUINT64)0) / 10)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
ui64Num *= (FLMUINT64)10;
|
|
}
|
|
else
|
|
{
|
|
if( ui64Num > (~(FLMUINT64)0) / 16)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
ui64Num *= (FLMUINT64)16;
|
|
}
|
|
|
|
if( ui64Num > (~(FLMUINT64)0) - (FLMUINT64)uiIncrAmount)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
ui64Num += (FLMUINT64)uiIncrAmount;
|
|
bFirstChar = FALSE;
|
|
}
|
|
|
|
// If the number is negative, make sure it doesn't
|
|
// overflow the maximum negative number.
|
|
|
|
if( bNeg)
|
|
{
|
|
if( ui64Num > gv_ui64MaxSignedIntVal + 1)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_UNDERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = setINT64( (IF_Db *)pDb,
|
|
-((FLMINT64)ui64Num), uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = setUINT64( (IF_Db *)pDb, ui64Num, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Store text as a binary value.
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::storeTextAsBinary(
|
|
F_Db * pDb,
|
|
const void * pvValue,
|
|
FLMUINT uiNumBytesInBuffer,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE ucBuf[ 64];
|
|
F_AsciiIStream asciiStream( (FLMBYTE *)pvValue,
|
|
uiNumBytesInBuffer, XFLM_UTF8_TEXT);
|
|
IF_IStream * pDecoderStream = NULL;
|
|
FLMBYTE ucDynaBuf[ 64];
|
|
F_DynaBuf dynaBuf( ucDynaBuf, sizeof( ucDynaBuf));
|
|
FLMUINT uiBytesRead;
|
|
|
|
if( RC_BAD( rc = FlmOpenBase64DecoderIStream(
|
|
&asciiStream, &pDecoderStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
for( ;;)
|
|
{
|
|
if( RC_BAD( rc = pDecoderStream->read( ucBuf, sizeof( ucBuf), &uiBytesRead)))
|
|
{
|
|
if( rc != NE_XFLM_EOF_HIT)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_XFLM_OK;
|
|
break;
|
|
}
|
|
|
|
if( RC_BAD( rc = dynaBuf.appendData( ucBuf, uiBytesRead)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = setBinary(
|
|
(IF_Db *)pDb, dynaBuf.getBufferPtr(),
|
|
dynaBuf.getDataLength(), uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pDecoderStream)
|
|
{
|
|
pDecoderStream->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Store binary as a text value (base 64 encoded)
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::storeBinaryAsText(
|
|
F_Db * pDb,
|
|
const void * pvValue,
|
|
FLMUINT uiLength,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE ucBuf[ 64];
|
|
IF_PosIStream * pIStream = NULL;
|
|
IF_IStream * pEncoderStream = NULL;
|
|
FLMBYTE ucDynaBuf[ 64];
|
|
F_DynaBuf dynaBuf( ucDynaBuf, sizeof( ucDynaBuf));
|
|
FLMUINT uiBytesRead;
|
|
|
|
if( RC_BAD( rc = FlmOpenBufferIStream(
|
|
(const char *)pvValue, uiLength, &pIStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmOpenBase64EncoderIStream( pIStream,
|
|
FALSE, &pEncoderStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
for( ;;)
|
|
{
|
|
if( RC_BAD( rc = pEncoderStream->read(
|
|
ucBuf, sizeof( ucBuf), &uiBytesRead)))
|
|
{
|
|
if( rc != NE_XFLM_EOF_HIT)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_XFLM_OK;
|
|
break;
|
|
}
|
|
|
|
if( RC_BAD( rc = dynaBuf.appendData( ucBuf, uiBytesRead)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = setTextFastPath( pDb, dynaBuf.getBufferPtr(),
|
|
dynaBuf.getDataLength(), XFLM_UTF8_TEXT, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pEncoderStream)
|
|
{
|
|
pEncoderStream->Release();
|
|
}
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::setTextStreaming(
|
|
F_Db * pDb,
|
|
const void * pvValue,
|
|
FLMUINT uiNumBytesInBuffer,
|
|
eXFlmTextType eTextType,
|
|
FLMBOOL bLast,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiLen;
|
|
FLMBYTE * pucUpdBuffer;
|
|
FLMUINT uiUpdBufferSize;
|
|
FLMBYTE * pucTmp;
|
|
FLMUINT uiSenLen;
|
|
FLMBYTE ucTmpSen[ FLM_MAX_NUM_BUF_SIZE];
|
|
F_Database * pDatabase = pDb->m_pDatabase;
|
|
F_Rfl * pRfl = pDatabase->m_pRfl;
|
|
F_DOMNode * pNode = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMBOOL bFirst = pDatabase->m_pPendingInput ? FALSE : TRUE;
|
|
FLMUINT uiRflToken = 0;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
// Not supported on attributes
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// If this is an element node, we need to find or create
|
|
// the child data node
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
// The streaming interface is not directly supported on element nodes.
|
|
// If the node already has a value and does not already have a child data
|
|
// node, we can clear the value on the element, create a data node, and
|
|
// allow the operation to continue.
|
|
|
|
if( getDataLength())
|
|
{
|
|
if( getDataChildCount())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = clearNodeValue( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( getDataChildCount())
|
|
{
|
|
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !pNode)
|
|
{
|
|
if( RC_BAD( rc = createNode( (IF_Db *)pDb, DATA_NODE,
|
|
getNameId(), XFLM_LAST_CHILD, (IF_DOMNode **)&pNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNode->setTextStreaming( pDb,
|
|
pvValue, uiNumBytesInBuffer, eTextType, bLast, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the state of the node and database
|
|
// allow a value to be set.
|
|
|
|
if( RC_BAD( rc = canSetValue( pDb, XFLM_TEXT_TYPE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
|
|
bMustAbortOnError = TRUE;
|
|
|
|
// If we are in the middle of streaming data into a node,
|
|
// any error will probably leave the database in a bad
|
|
// state. Because of this, we want to force the
|
|
// transaction to abort.
|
|
|
|
if( pDatabase->m_pPendingInput)
|
|
{
|
|
if( pDatabase->m_pPendingInput != m_pCachedNode)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pucUpdBuffer = pDatabase->m_pucUpdBuffer;
|
|
|
|
// NOTE: So that flushNode would not have to allocate a buffer for
|
|
// writing out data with a non-padded header, we reserve enough
|
|
// room in pDatabase->m_pucUpdBuffer so that it could hold a maximum
|
|
// header plus all of the data if it needed to.
|
|
// Also, make sure there is room to encrypt the data. That is why
|
|
// we subtract another 16 bytes.
|
|
|
|
uiUpdBufferSize = pDatabase->m_uiUpdBufferSize -
|
|
MAX_DOM_HEADER_SIZE - ENCRYPT_MIN_CHUNK_SIZE;
|
|
|
|
// Update the index keys
|
|
|
|
if( bFirst)
|
|
{
|
|
if( getNameId())
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_DEL_NODE_VALUE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Open the pending input stream
|
|
|
|
if( bFirst)
|
|
{
|
|
if( RC_BAD( rc = openPendingInput( pDb, XFLM_TEXT_TYPE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Reserve 5 bytes for a SEN indicating the number of characters
|
|
// in the string. The SEN (representing a 32-bit number) will
|
|
// never require more than 5 bytes and will typically only
|
|
// require 1 or 2 bytes.
|
|
|
|
pDatabase->m_uiUpdByteCount += SEN_RESERVE_BYTES;
|
|
*pucUpdBuffer = 0;
|
|
|
|
// Save the encryption scheme
|
|
|
|
setEncDefId( uiEncDefId);
|
|
}
|
|
|
|
// Set the value
|
|
|
|
if( pvValue)
|
|
{
|
|
// If a zero was passed for the character count, change it to
|
|
// the UINT high value. We will output characters until a terminating
|
|
// null is found.
|
|
|
|
if( !uiNumBytesInBuffer)
|
|
{
|
|
uiNumBytesInBuffer = FLM_MAX_UINT;
|
|
}
|
|
|
|
switch( eTextType)
|
|
{
|
|
case XFLM_UNICODE_TEXT:
|
|
{
|
|
FLMUNICODE * puCurChar = (FLMUNICODE *)pvValue;
|
|
|
|
while( *puCurChar && uiNumBytesInBuffer >= sizeof( FLMUNICODE))
|
|
{
|
|
uiLen = uiUpdBufferSize - pDatabase->m_uiUpdByteCount;
|
|
if( RC_BAD( rc = f_uni2UTF8( *puCurChar,
|
|
&pucUpdBuffer[ pDatabase->m_uiUpdByteCount], &uiLen)))
|
|
{
|
|
if( rc == NE_XFLM_CONV_DEST_OVERFLOW)
|
|
{
|
|
if( RC_BAD( rc = flushPendingInput( pDb, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
pDatabase->m_uiUpdByteCount += uiLen;
|
|
pDatabase->m_uiUpdCharCount++;
|
|
uiNumBytesInBuffer -= sizeof( FLMUNICODE);
|
|
puCurChar++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XFLM_UTF8_TEXT:
|
|
{
|
|
FLMBYTE * pucCurByte = (FLMBYTE *)pvValue;
|
|
FLMBYTE * pucEnd = (FLMBYTE *)pvValue + uiNumBytesInBuffer;
|
|
|
|
for( ;;)
|
|
{
|
|
if( (uiUpdBufferSize - pDatabase->m_uiUpdByteCount) < 3)
|
|
{
|
|
if( RC_BAD( rc = flushPendingInput( pDb, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = f_getUTF8CharFromUTF8Buf( &pucCurByte,
|
|
pucEnd, &pucUpdBuffer[ pDatabase->m_uiUpdByteCount], &uiLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !uiLen)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pDatabase->m_uiUpdByteCount += uiLen;
|
|
pDatabase->m_uiUpdCharCount++;
|
|
uiNumBytesInBuffer -= uiLen;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bLast)
|
|
{
|
|
// Terminate the buffer with a null byte
|
|
|
|
if( pDatabase->m_uiUpdCharCount)
|
|
{
|
|
// See if there is room for a single zero byte
|
|
|
|
if( pDatabase->m_uiUpdByteCount == uiUpdBufferSize)
|
|
{
|
|
if( RC_BAD( rc = flushPendingInput( pDb, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pucUpdBuffer[ pDatabase->m_uiUpdByteCount++] = 0;
|
|
}
|
|
|
|
if( pDatabase->m_bUpdFirstBuf)
|
|
{
|
|
if( pDatabase->m_uiUpdCharCount)
|
|
{
|
|
FLMUINT uiValLen;
|
|
|
|
// Five bytes were reserved to encode the number of characters
|
|
// in the string. Since we didn't have to use multiple buffers
|
|
// to write the string to the database, we won't have to
|
|
// output a padded SEN.
|
|
|
|
pucTmp = ucTmpSen;
|
|
f_encodeSEN( pDatabase->m_uiUpdCharCount, &pucTmp);
|
|
uiSenLen = (FLMUINT)(pucTmp - ucTmpSen);
|
|
|
|
// Copy the value into the node
|
|
|
|
uiValLen = (pDatabase->m_uiUpdByteCount -
|
|
SEN_RESERVE_BYTES) + uiSenLen;
|
|
|
|
if( calcDataBufSize( uiValLen) > getDataBufSize())
|
|
{
|
|
if( RC_BAD( rc = resizeDataBuffer( uiValLen, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
setDataLength( uiValLen);
|
|
f_memcpy( getDataPtr(), ucTmpSen, uiSenLen);
|
|
f_memcpy( getDataPtr() + uiSenLen,
|
|
&pucUpdBuffer[ SEN_RESERVE_BYTES],
|
|
pDatabase->m_uiUpdByteCount - SEN_RESERVE_BYTES);
|
|
}
|
|
else
|
|
{
|
|
setDataLength( 0);
|
|
}
|
|
|
|
// Clear flags
|
|
|
|
unsetFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
setDataLength( 0);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
|
|
FLMUINT uiKeyLen;
|
|
FLMUINT uiHeaderStorageSize;
|
|
FLMUINT32 ui32BlkAddr;
|
|
FLMUINT uiOffsetIndex;
|
|
|
|
// Flush anything that is in the current buffer and end the
|
|
// pending input stream.
|
|
|
|
if( RC_BAD( rc = flushPendingInput( pDb, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pucTmp = ucTmpSen;
|
|
f_encodeSEN( pDatabase->m_uiUpdCharCount,
|
|
&pucTmp, SEN_RESERVE_BYTES);
|
|
flmAssert( (FLMUINT)(pucTmp - ucTmpSen) == SEN_RESERVE_BYTES);
|
|
|
|
// Output the header
|
|
|
|
if( RC_BAD( rc = headerToBuf( TRUE, pDatabase->m_pucUpdBuffer,
|
|
&uiHeaderStorageSize, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Copy the SEN into the update buffer
|
|
|
|
f_memcpy( &pDatabase->m_pucUpdBuffer[ uiHeaderStorageSize],
|
|
ucTmpSen, SEN_RESERVE_BYTES);
|
|
|
|
// Replace the header
|
|
|
|
uiKeyLen = sizeof( ucKey);
|
|
if( RC_BAD( rc = flmNumber64ToStorage( getNodeId(), &uiKeyLen,
|
|
ucKey, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ui32BlkAddr = getBlkAddr();
|
|
uiOffsetIndex = getOffsetIndex();
|
|
|
|
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btReplaceEntry(
|
|
ucKey, uiKeyLen,
|
|
pDatabase->m_pucUpdBuffer, uiHeaderStorageSize + SEN_RESERVE_BYTES,
|
|
TRUE, TRUE, FALSE, &ui32BlkAddr, &uiOffsetIndex)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
setBlkAddr( ui32BlkAddr);
|
|
setOffsetIndex( uiOffsetIndex);
|
|
|
|
// Clear the dirty flag and the new flag.
|
|
|
|
unsetNodeDirtyAndNew( pDb);
|
|
}
|
|
|
|
pDatabase->endPendingInput();
|
|
|
|
if( getNameId())
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_ADD_NODE_VALUE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Log the node to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeSetValue( pDb,
|
|
RFL_NODE_SET_TEXT_VALUE_PACKET, m_pCachedNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDatabase->endPendingInput();
|
|
|
|
if( bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::setTextFastPath(
|
|
F_Db * pDb,
|
|
const void * pvValue,
|
|
FLMUINT uiNumBytesInBuffer,
|
|
eXFlmTextType eTextType,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiNumCharsInBuffer = 0;
|
|
FLMBYTE ucUTFCharBuf[ 3];
|
|
F_Database * pDatabase = pDb->m_pDatabase;
|
|
F_Rfl * pRfl = pDatabase->m_pRfl;
|
|
F_DOMNode * pNode = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMUINT uiValLen;
|
|
FLMUINT uiReadLen;
|
|
FLMBOOL bIsIndexed = TRUE;
|
|
FLMBYTE ucDynaBuf[ 64];
|
|
F_DynaBuf dynaBuf( ucDynaBuf, sizeof( ucDynaBuf));
|
|
FLMBOOL bStartOfUpdate = TRUE;
|
|
eDomNodeType eNodeType;
|
|
|
|
// Make sure a transaction is active
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Cannot set a value if input is still pending
|
|
|
|
if( pDatabase->m_pPendingInput)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
// Convert the text to UTF-8 if needed
|
|
|
|
if( eTextType == XFLM_UNICODE_TEXT)
|
|
{
|
|
FLMUNICODE * puCurChar = (FLMUNICODE *)pvValue;
|
|
|
|
if( puCurChar)
|
|
{
|
|
if( !uiNumBytesInBuffer)
|
|
{
|
|
uiNumBytesInBuffer = FLM_MAX_UINT;
|
|
}
|
|
|
|
while( *puCurChar && uiNumBytesInBuffer >= sizeof( FLMUNICODE))
|
|
{
|
|
if( *puCurChar <= 0x007F)
|
|
{
|
|
if( RC_BAD( rc = dynaBuf.appendByte( (FLMBYTE)*puCurChar)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiReadLen = sizeof( ucUTFCharBuf);
|
|
if( RC_BAD( rc = f_uni2UTF8( *puCurChar,
|
|
ucUTFCharBuf, &uiReadLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = dynaBuf.appendData( ucUTFCharBuf, uiReadLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
puCurChar++;
|
|
uiNumBytesInBuffer -= sizeof( FLMUNICODE);
|
|
uiNumCharsInBuffer++;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = dynaBuf.appendByte( 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eTextType = XFLM_UTF8_TEXT;
|
|
pvValue = dynaBuf.getBufferPtr();
|
|
uiNumBytesInBuffer = dynaBuf.getDataLength();
|
|
}
|
|
else if( eTextType == XFLM_UTF8_TEXT)
|
|
{
|
|
if( RC_BAD( rc = f_getUTF8Length( (FLMBYTE *)pvValue, uiNumBytesInBuffer,
|
|
&uiNumBytesInBuffer, &uiNumCharsInBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// If this is an element node, we need to see if there is a
|
|
// child data node
|
|
|
|
if( eNodeType == ELEMENT_NODE && getDataChildCount())
|
|
{
|
|
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( getDataChildCount() == 1)
|
|
{
|
|
// If this node only has one data child, delete the child and
|
|
// store the value directly on the element
|
|
|
|
if( RC_BAD( rc = pNode->deleteNode( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pNode->Release();
|
|
pNode = NULL;
|
|
}
|
|
else
|
|
{
|
|
rc = pNode->setTextFastPath( pDb, pvValue, uiNumBytesInBuffer,
|
|
eTextType, uiEncDefId);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Make sure the states of the node and database
|
|
// allow a value to be set.
|
|
|
|
if( RC_BAD( rc = canSetValue( pDb, XFLM_TEXT_TYPE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If this is an attribute node, need to use the
|
|
// attribute list object to set the value
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_DEL_NODE_VALUE, bStartOfUpdate,
|
|
&bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->setUTF8( pDb,
|
|
m_uiAttrNameId, pvValue, uiNumBytesInBuffer,
|
|
uiNumCharsInBuffer, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
setDataLength( 0);
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the value to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
|
|
m_pCachedNode, m_uiAttrNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
|
|
bMustAbortOnError = TRUE;
|
|
|
|
// Update the index keys
|
|
|
|
if( getNameId())
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bIsIndexed = FALSE;
|
|
}
|
|
|
|
// Verify and save the encryption scheme
|
|
|
|
if( uiEncDefId)
|
|
{
|
|
if( RC_BAD( rc = pDb->m_pDict->getEncDef( uiEncDefId, NULL)))
|
|
{
|
|
flmAssert( 0);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
setEncDefId( uiEncDefId);
|
|
|
|
// Set the value
|
|
|
|
uiValLen = 0;
|
|
|
|
if( pvValue && uiNumBytesInBuffer)
|
|
{
|
|
FLMUINT uiSenLen;
|
|
FLMBYTE * pucTmp;
|
|
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
|
|
FLMBOOL bNullTerminate = FALSE;
|
|
|
|
if( pucValue[ uiNumBytesInBuffer - 1] != 0)
|
|
{
|
|
bNullTerminate = TRUE;
|
|
}
|
|
|
|
uiSenLen = f_getSENByteCount( uiNumCharsInBuffer);
|
|
uiValLen = uiNumBytesInBuffer + uiSenLen + (bNullTerminate ? 1 : 0);
|
|
|
|
if( calcDataBufSize( uiValLen) > getDataBufSize())
|
|
{
|
|
if( RC_BAD( rc = resizeDataBuffer( uiValLen, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pucTmp = getDataPtr();
|
|
f_encodeSENKnownLength( uiNumCharsInBuffer, uiSenLen, &pucTmp);
|
|
f_memcpy( pucTmp, pucValue, uiNumBytesInBuffer);
|
|
|
|
if( bNullTerminate)
|
|
{
|
|
pucTmp[ uiNumBytesInBuffer] = 0;
|
|
}
|
|
}
|
|
|
|
setDataLength( uiValLen);
|
|
|
|
// Clear flags
|
|
|
|
unsetFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
setDataLength( 0);
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
|
|
// Log the node to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeSetValue( pDb,
|
|
RFL_NODE_SET_TEXT_VALUE_PACKET, m_pCachedNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
if( bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::setBinaryStreaming(
|
|
IF_Db * ifpDb,
|
|
const void * pvValue,
|
|
FLMUINT uiLength,
|
|
FLMBOOL bLast,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Database * pDatabase = pDb->m_pDatabase;
|
|
F_Rfl * pRfl = pDatabase->m_pRfl;
|
|
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
|
|
FLMBYTE * pucUpdBuffer;
|
|
FLMUINT uiUpdBufferSize;
|
|
FLMUINT uiTmp;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DOMNode * pNode = NULL;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
// Not supported on attribute nodes
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// If this is an element node, we need to find or create
|
|
// the child data node
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
// The streaming interface is not directly supported on element nodes.
|
|
// If the node already has a value and does not already have a child data
|
|
// node, we can clear the value on the element, create a data node, and
|
|
// allow the operation to continue.
|
|
|
|
if( getDataLength())
|
|
{
|
|
if( getDataChildCount())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = clearNodeValue( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( getDataChildCount())
|
|
{
|
|
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !pNode)
|
|
{
|
|
if( RC_BAD( rc = createNode( (IF_Db *)pDb, DATA_NODE,
|
|
getNameId(), XFLM_LAST_CHILD, (IF_DOMNode **)&pNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNode->setBinary( ifpDb, pucValue, uiLength, bLast,
|
|
uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the state of the node and database
|
|
// allow a value to be set.
|
|
|
|
if( RC_BAD( rc = canSetValue( pDb, XFLM_BINARY_TYPE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
|
|
bMustAbortOnError = TRUE;
|
|
|
|
// If we are in the middle of streaming data into a node,
|
|
// any error will probably leave the database in a bad
|
|
// state. Because of this, we want to force the
|
|
// transaction to abort.
|
|
|
|
if( pDatabase->m_pPendingInput)
|
|
{
|
|
if( pDatabase->m_pPendingInput != m_pCachedNode)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pucUpdBuffer = pDatabase->m_pucUpdBuffer;
|
|
|
|
// NOTE: So that flushNode would not have to allocate a buffer for
|
|
// writing out data with a non-padded header, we reserve enough
|
|
// room in pDatabase->m_pucUpdBuffer so that it could hold a maximum
|
|
// header plus all of the data if it needed to.
|
|
//
|
|
// Also, make sure there is room to encrypt the data. That is why
|
|
// we subtract another 16 bytes.
|
|
|
|
uiUpdBufferSize = pDatabase->m_uiUpdBufferSize -
|
|
MAX_DOM_HEADER_SIZE - ENCRYPT_MIN_CHUNK_SIZE;
|
|
|
|
// Open the pending input stream
|
|
|
|
if( !pDatabase->m_pPendingInput)
|
|
{
|
|
if( getNameId())
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
|
|
this, IX_DEL_NODE_VALUE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = openPendingInput( pDb, XFLM_BINARY_TYPE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Save the encryption scheme
|
|
|
|
setEncDefId( uiEncDefId);
|
|
|
|
while( uiLength)
|
|
{
|
|
if( (uiTmp = f_min( uiLength,
|
|
uiUpdBufferSize - pDatabase->m_uiUpdByteCount)) == 0)
|
|
{
|
|
if( RC_BAD( rc = flushPendingInput( pDb, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
f_memcpy( &pucUpdBuffer[ pDatabase->m_uiUpdByteCount], pucValue, uiTmp);
|
|
pDatabase->m_uiUpdByteCount += uiTmp;
|
|
pucValue += uiTmp;
|
|
uiLength -= uiTmp;
|
|
}
|
|
|
|
if( bLast)
|
|
{
|
|
if( pDatabase->m_bUpdFirstBuf)
|
|
{
|
|
if( pDatabase->m_uiUpdByteCount)
|
|
{
|
|
if( calcDataBufSize( pDatabase->m_uiUpdByteCount) > getDataBufSize())
|
|
{
|
|
if( RC_BAD( rc = resizeDataBuffer(
|
|
pDatabase->m_uiUpdByteCount, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
setDataLength( pDatabase->m_uiUpdByteCount);
|
|
|
|
if( pDatabase->m_uiUpdByteCount)
|
|
{
|
|
f_memcpy( getDataPtr(), pucUpdBuffer, pDatabase->m_uiUpdByteCount);
|
|
}
|
|
|
|
// Clear unwanted flags
|
|
|
|
unsetFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
|
|
FLMUINT uiKeyLen;
|
|
FLMUINT uiHeaderStorageSize;
|
|
FLMUINT32 ui32BlkAddr;
|
|
FLMUINT uiOffsetIndex;
|
|
|
|
// Flush anything that is in the current buffer
|
|
|
|
if( RC_BAD( rc = flushPendingInput( pDb, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Output the header
|
|
|
|
if( RC_BAD( rc = headerToBuf( TRUE, pDatabase->m_pucUpdBuffer,
|
|
&uiHeaderStorageSize, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Replace the header
|
|
|
|
uiKeyLen = sizeof( ucKey);
|
|
if( RC_BAD( rc = flmNumber64ToStorage( getNodeId(), &uiKeyLen,
|
|
ucKey, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ui32BlkAddr = getBlkAddr();
|
|
uiOffsetIndex = getOffsetIndex();
|
|
|
|
if( RC_BAD( rc = pDatabase->m_pPendingBTree->btReplaceEntry(
|
|
ucKey, uiKeyLen,
|
|
pDatabase->m_pucUpdBuffer, uiHeaderStorageSize,
|
|
TRUE, TRUE, FALSE, &ui32BlkAddr, &uiOffsetIndex)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
setBlkAddr( ui32BlkAddr);
|
|
setOffsetIndex( uiOffsetIndex);
|
|
|
|
// Clear the dirty flag and the new flag.
|
|
|
|
unsetNodeDirtyAndNew( pDb);
|
|
}
|
|
|
|
pDatabase->endPendingInput();
|
|
|
|
if( getNameId())
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
|
|
this, IX_ADD_NODE_VALUE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Log the node to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeSetValue( pDb,
|
|
RFL_NODE_SET_BINARY_VALUE_PACKET, m_pCachedNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDatabase->endPendingInput();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::setBinaryFastPath(
|
|
IF_Db * ifpDb,
|
|
const void * pvValue,
|
|
FLMUINT uiLength,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Database * pDatabase = pDb->m_pDatabase;
|
|
F_Rfl * pRfl = pDatabase->m_pRfl;
|
|
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DOMNode * pNode = NULL;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
eDomNodeType eNodeType;
|
|
FLMBOOL bIsIndexed = TRUE;
|
|
FLMBOOL bStartOfUpdate = TRUE;
|
|
|
|
// Make sure a transaction is active
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Cannot set a value if input is still pending
|
|
|
|
if( pDatabase->m_pPendingInput)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
// If this is an element node, we need to find or create
|
|
// the child data node
|
|
|
|
if( eNodeType == ELEMENT_NODE && getDataChildCount())
|
|
{
|
|
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( getDataChildCount() == 1)
|
|
{
|
|
// If this node only has one data child, delete the child and
|
|
// store the value directly on the element
|
|
|
|
if( RC_BAD( rc = pNode->deleteNode( ifpDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pNode->Release();
|
|
pNode = NULL;
|
|
}
|
|
else
|
|
{
|
|
rc = pNode->setBinaryFastPath( ifpDb, pucValue, uiLength, uiEncDefId);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
// Make sure the state of the node and database
|
|
// allow a value to be set.
|
|
|
|
if( RC_BAD( rc = canSetValue( pDb, XFLM_BINARY_TYPE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( (F_Db *)ifpDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
|
|
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->setBinary(
|
|
pDb, m_uiAttrNameId, pvValue, uiLength, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
getCollection(), this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the value to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
|
|
m_pCachedNode, m_uiAttrNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
// If node is a text data type, convert the binary to base 64 encoding
|
|
// and store as text.
|
|
|
|
if( getDataType() == XFLM_TEXT_TYPE)
|
|
{
|
|
// Convert to base64 text and call the routine to set as native.
|
|
|
|
rc = storeBinaryAsText( (F_Db *)ifpDb, pvValue, uiLength, uiEncDefId);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the state of the node and database
|
|
// allow a value to be set.
|
|
|
|
if( RC_BAD( rc = canSetValue( pDb, XFLM_BINARY_TYPE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
unsetFlags( FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
|
|
|
|
if( getNameId())
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
|
|
this, IX_DEL_NODE_VALUE, bStartOfUpdate, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bIsIndexed = FALSE;
|
|
}
|
|
|
|
setEncDefId( uiEncDefId);
|
|
|
|
if( calcDataBufSize( uiLength) > getDataBufSize())
|
|
{
|
|
if( RC_BAD( rc = resizeDataBuffer( uiLength, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
setDataLength( uiLength);
|
|
|
|
if( uiLength)
|
|
{
|
|
f_memcpy( getDataPtr(), pvValue, uiLength);
|
|
}
|
|
|
|
// Clear unwanted flags
|
|
|
|
unsetFlags( FDOM_VALUE_ON_DISK | FDOM_FIXED_SIZE_HEADER);
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
|
|
this, IX_ADD_NODE_VALUE, bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
|
|
// Log the node to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeSetValue( pDb,
|
|
RFL_NODE_SET_BINARY_VALUE_PACKET, m_pCachedNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::clearNodeValue(
|
|
F_Db * pDb)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Database * pDatabase = pDb->m_pDatabase;
|
|
F_Rfl * pRfl = pDatabase->m_pRfl;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
|
|
// Make sure a transaction is active
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Cannot clear a value if input is still pending
|
|
|
|
if( pDatabase->m_pPendingInput)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = setStorageValue( pDb, NULL, 0, 0, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the update to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeClearValue( pDb, getCollection(),
|
|
getNodeId(), m_uiAttrNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::getIStream(
|
|
F_Db * pDb,
|
|
F_NodeBufferIStream * pStackStream,
|
|
IF_PosIStream ** ppIStream,
|
|
FLMUINT * puiDataType,
|
|
FLMUINT * puiDataLength)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
IF_PosIStream * pIStream = NULL;
|
|
F_DOMNode * pNode = NULL;
|
|
F_CachedNode * pCachedNode = this;
|
|
eDomNodeType eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
if( m_uiFlags & FDOM_VALUE_ON_DISK)
|
|
{
|
|
F_BTreeIStream * pBTreeIStream;
|
|
F_ENCDEF * pEncDef;
|
|
FLMUINT uiIVLen;
|
|
FLMUINT uiLen;
|
|
F_NODE_INFO nodeInfo;
|
|
FLMUINT uiTmpFlags;
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->flushDirtyNode( this)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodePool->allocBTreeIStream(
|
|
&pBTreeIStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pIStream = pBTreeIStream;
|
|
|
|
if( RC_BAD( rc = pBTreeIStream->open( pDb, getCollection(),
|
|
getNodeId(), getBlkAddr(), getOffsetIndex())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Skip the node header
|
|
|
|
if( RC_BAD( rc = flmReadNodeInfo( getCollection(), getNodeId(),
|
|
pBTreeIStream, (FLMUINT)pBTreeIStream->remainingSize(), TRUE,
|
|
&nodeInfo, &uiTmpFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Read the IV if data is encrypted
|
|
|
|
if( getEncDefId())
|
|
{
|
|
if( RC_BAD( rc = pDb->m_pDict->getEncDef( getEncDefId(), &pEncDef)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiIVLen = pEncDef->pCcs->getIVLen();
|
|
flmAssert( uiIVLen == 8 || uiIVLen == 16);
|
|
|
|
if( RC_BAD( rc = pBTreeIStream->read( (char *)pBTreeIStream->m_ucIV,
|
|
uiIVLen, &uiLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( uiLen == uiIVLen);
|
|
pBTreeIStream->m_bDataEncrypted = TRUE;
|
|
}
|
|
|
|
pBTreeIStream->m_uiEncDefId = getEncDefId();
|
|
pBTreeIStream->m_uiDataLength = getDataLength();
|
|
}
|
|
else
|
|
{
|
|
F_NodeBufferIStream * pNodeBufferIStream;
|
|
FLMUINT64 ui64TmpNodeId;
|
|
|
|
if( eNodeType == ELEMENT_NODE && getDataChildCount())
|
|
{
|
|
ui64TmpNodeId = getFirstChildId();
|
|
|
|
for( ;;)
|
|
{
|
|
if( !ui64TmpNodeId)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
|
|
getCollection(), ui64TmpNodeId, (IF_DOMNode **)&pNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pNode->getNodeType() == DATA_NODE)
|
|
{
|
|
pCachedNode = pNode->m_pCachedNode;
|
|
break;
|
|
}
|
|
|
|
ui64TmpNodeId = pNode->getNextSibId();
|
|
}
|
|
}
|
|
|
|
if( pStackStream)
|
|
{
|
|
pNodeBufferIStream = pStackStream;
|
|
pStackStream->AddRef();
|
|
flmAssert( !pStackStream->m_pCachedNode);
|
|
}
|
|
else
|
|
{
|
|
if( (pNodeBufferIStream = f_new F_NodeBufferIStream) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_MEM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pIStream = pNodeBufferIStream;
|
|
|
|
if( RC_BAD( rc = pNodeBufferIStream->open(
|
|
(const char *)pCachedNode->getDataPtr(),
|
|
pCachedNode->getDataLength())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pStackStream)
|
|
{
|
|
pNodeBufferIStream->m_pCachedNode = pCachedNode;
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
pCachedNode->incrNodeUseCount();
|
|
pCachedNode->incrStreamUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
}
|
|
}
|
|
|
|
if( puiDataType)
|
|
{
|
|
*puiDataType = pCachedNode->getDataType();
|
|
}
|
|
|
|
if( puiDataLength)
|
|
{
|
|
*puiDataLength = pCachedNode->getDataLength();
|
|
}
|
|
|
|
*ppIStream = pIStream;
|
|
pIStream = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::getRawIStream(
|
|
F_Db * pDb,
|
|
IF_PosIStream ** ppIStream)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
IF_PosIStream * pIStream = NULL;
|
|
F_BTreeIStream * pBTreeIStream;
|
|
eDomNodeType eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// Flush all dirty nodes out to the B-Tree
|
|
|
|
if( RC_BAD( rc = pDb->flushDirtyNode( this)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodePool->allocBTreeIStream(
|
|
&pBTreeIStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pIStream = pBTreeIStream;
|
|
|
|
if( RC_BAD( rc = pBTreeIStream->open( pDb, getCollection(),
|
|
getNodeId(), getBlkAddr(), getOffsetIndex())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*ppIStream = pIStream;
|
|
pIStream = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getIStream(
|
|
F_Db * pDb,
|
|
F_NodeBufferIStream * pStackStream,
|
|
IF_PosIStream ** ppIStream,
|
|
FLMUINT * puiDataType,
|
|
FLMUINT * puiDataLength)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pNode = NULL;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Sync the node to make sure it is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
switch( getNodeType())
|
|
{
|
|
case DATA_NODE:
|
|
case COMMENT_NODE:
|
|
case ANNOTATION_NODE:
|
|
case CDATA_SECTION_NODE:
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getIStream( pDb, pStackStream,
|
|
ppIStream, puiDataType, puiDataLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ELEMENT_NODE:
|
|
{
|
|
if( getDataChildCount())
|
|
{
|
|
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNode->m_pCachedNode->getIStream( pDb,
|
|
pStackStream, ppIStream, puiDataType, puiDataLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getIStream( pDb,
|
|
pStackStream, ppIStream, puiDataType, puiDataLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ATTRIBUTE_NODE:
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getIStream(
|
|
pDb, m_uiAttrNameId, pStackStream, ppIStream,
|
|
puiDataType, puiDataLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getTextIStream(
|
|
F_Db * pDb,
|
|
F_NodeBufferIStream * pStackStream,
|
|
IF_PosIStream ** ppIStream,
|
|
FLMUINT * puiNumChars)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiDataType;
|
|
|
|
*ppIStream = NULL;
|
|
*puiNumChars = 0;
|
|
|
|
if( RC_BAD( rc = getIStream( pDb, pStackStream, ppIStream, &uiDataType)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiDataType != XFLM_TEXT_TYPE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_DATA_TYPE);
|
|
goto Exit;
|
|
}
|
|
|
|
// Skip the leading SEN so that the stream is positioned to
|
|
// read raw utf8.
|
|
|
|
if( (*ppIStream)->remainingSize())
|
|
{
|
|
if( RC_BAD( rc = f_readSEN( *ppIStream, puiNumChars)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc) && *ppIStream)
|
|
{
|
|
(*ppIStream)->Release();
|
|
*ppIStream = NULL;
|
|
*puiNumChars = 0;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getNumber64(
|
|
F_Db * pDb,
|
|
FLMUINT64 * pui64Num,
|
|
FLMBOOL * pbNeg)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiDataType;
|
|
FLMUINT64 ui64Num;
|
|
FLMBOOL bNeg;
|
|
F_DOMNode * pNode = NULL;
|
|
eDomNodeType eNodeType;
|
|
IF_PosIStream * pIStream = NULL;
|
|
F_NodeBufferIStream bufferIStream;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getNumber64(
|
|
pDb, m_uiAttrNameId, &ui64Num, &bNeg)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if ( !getQuickNumber64( &ui64Num, &bNeg))
|
|
{
|
|
if( eNodeType == ELEMENT_NODE && getDataChildCount())
|
|
{
|
|
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
rc = pNode->getNumber64( pDb, pui64Num, pbNeg);
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = getIStream( pDb, &bufferIStream,
|
|
&pIStream, &uiDataType)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmReadStorageAsNumber( pIStream, uiDataType,
|
|
&ui64Num, &bNeg)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pui64Num)
|
|
{
|
|
*pui64Num = ui64Num;
|
|
}
|
|
|
|
if( pbNeg)
|
|
{
|
|
*pbNeg = bNeg;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Allocate data for a unicode element and retrieve it.
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getUnicode(
|
|
IF_Db * ifpDb,
|
|
FLMUNICODE ** ppuzUnicode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiLen;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Get the unicode length (does not include NULL terminator)
|
|
|
|
if( RC_BAD( rc = getUnicodeChars( pDb, &uiLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiLen)
|
|
{
|
|
FLMUINT uiBufSize = (uiLen + 1) * sizeof( FLMUNICODE);
|
|
|
|
if( RC_BAD( rc = f_alloc( uiBufSize, ppuzUnicode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getUnicode( pDb,
|
|
*ppuzUnicode, uiBufSize, 0, uiLen, &uiLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppuzUnicode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getUnicode(
|
|
IF_Db * ifpDb,
|
|
FLMUNICODE * puzBuffer,
|
|
FLMUINT uiBufSize,
|
|
FLMUINT uiCharOffset,
|
|
FLMUINT uiMaxCharsRequested,
|
|
FLMUINT * puiCharsReturned,
|
|
FLMUINT * puiBufferBytesUsed)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiDataType;
|
|
FLMUINT uiDataLength;
|
|
F_NodeBufferIStream bufferStream;
|
|
IF_PosIStream * pIStream = NULL;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getIStream( pDb, &bufferStream,
|
|
&pIStream, &uiDataType, &uiDataLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmReadStorageAsText(
|
|
pIStream, NULL, uiDataLength, uiDataType, puzBuffer,
|
|
uiBufSize, XFLM_UNICODE_TEXT,
|
|
uiMaxCharsRequested, uiCharOffset, puiCharsReturned,
|
|
puiBufferBytesUsed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getUnicode(
|
|
IF_Db * ifpDb,
|
|
F_DynaBuf * pBuffer)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMUINT uiBufSize;
|
|
FLMUINT uiChars;
|
|
void * pvBuffer = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pBuffer->truncateData( 0);
|
|
|
|
if( RC_BAD( rc = getUnicode( ifpDb, NULL, 0, 0, ~((FLMUINT)0), &uiChars)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiBufSize = (uiChars + 1) * sizeof( FLMUNICODE);
|
|
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getUnicode( ifpDb, (FLMUNICODE *)pvBuffer, uiBufSize, 0,
|
|
~((FLMUINT)0), NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getUTF8(
|
|
IF_Db * ifpDb,
|
|
FLMBYTE * pszValue,
|
|
FLMUINT uiBufferSize,
|
|
FLMUINT uiCharOffset,
|
|
FLMUINT uiMaxCharsRequested,
|
|
FLMUINT * puiCharsReturned,
|
|
FLMUINT * puiBufferBytesUsed)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiDataType;
|
|
FLMUINT uiDataLength;
|
|
F_DOMNode * pNode = NULL;
|
|
IF_PosIStream * pIStream = NULL;
|
|
F_NodeBufferIStream bufferIStream;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
switch( getNodeType())
|
|
{
|
|
case DATA_NODE:
|
|
case COMMENT_NODE:
|
|
case ANNOTATION_NODE:
|
|
case CDATA_SECTION_NODE:
|
|
{
|
|
pNode = this;
|
|
pNode->AddRef();
|
|
break;
|
|
}
|
|
|
|
case ATTRIBUTE_NODE:
|
|
{
|
|
pNode = this;
|
|
pNode->AddRef();
|
|
goto SlowDecode;
|
|
}
|
|
|
|
case ELEMENT_NODE:
|
|
{
|
|
if( getDataChildCount())
|
|
{
|
|
if( RC_BAD( rc = getChild( pDb, DATA_NODE, (IF_DOMNode **)&pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNode = this;
|
|
pNode->AddRef();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( (pNode->getModeFlags() & FDOM_VALUE_ON_DISK) ||
|
|
pNode->getDataType() != XFLM_TEXT_TYPE || uiCharOffset)
|
|
{
|
|
SlowDecode:
|
|
|
|
if( RC_BAD( rc = pNode->getIStream( pDb, &bufferIStream, &pIStream,
|
|
&uiDataType, &uiDataLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmReadStorageAsText(
|
|
pIStream, NULL, uiDataLength,
|
|
uiDataType, pszValue, uiBufferSize, XFLM_UTF8_TEXT,
|
|
uiMaxCharsRequested, uiCharOffset, puiCharsReturned,
|
|
puiBufferBytesUsed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const FLMBYTE * pucBuffer = pNode->getDataPtr();
|
|
const FLMBYTE * pucEnd = pucBuffer + pNode->getDataLength();
|
|
FLMUINT uiCharCount = 0;
|
|
FLMUINT uiStrByteLen = 0;
|
|
|
|
if( pucBuffer)
|
|
{
|
|
if( RC_BAD( rc = f_decodeSEN( &pucBuffer, pucEnd, &uiCharCount)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiStrByteLen = (FLMUINT)(pucEnd - pucBuffer);
|
|
}
|
|
|
|
if( uiCharCount > uiMaxCharsRequested ||
|
|
(pszValue && uiBufferSize < uiStrByteLen))
|
|
{
|
|
goto SlowDecode;
|
|
}
|
|
|
|
if( pszValue)
|
|
{
|
|
if( uiStrByteLen)
|
|
{
|
|
f_memcpy( pszValue, pucBuffer, uiStrByteLen);
|
|
}
|
|
else if( uiBufferSize > 0)
|
|
{
|
|
*pszValue = 0;
|
|
}
|
|
}
|
|
|
|
if( puiCharsReturned)
|
|
{
|
|
*puiCharsReturned = uiCharCount;
|
|
}
|
|
|
|
if( puiBufferBytesUsed)
|
|
{
|
|
*puiBufferBytesUsed = uiStrByteLen;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getUTF8(
|
|
IF_Db * ifpDb,
|
|
FLMBYTE ** ppszUTF8)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMUINT uiBufSize;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getUTF8( ifpDb, NULL, 0, 0,
|
|
FLM_MAX_UINT, NULL, &uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiBufSize)
|
|
{
|
|
if( RC_BAD( rc = f_alloc( uiBufSize, ppszUTF8)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getUTF8( ifpDb, *ppszUTF8, uiBufSize, 0,
|
|
FLM_MAX_UINT, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppszUTF8 = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getUTF8(
|
|
IF_Db * ifpDb,
|
|
F_DynaBuf * pBuffer)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMUINT uiBufSize;
|
|
void * pvBuffer = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pBuffer->truncateData( 0);
|
|
|
|
if( RC_BAD( rc = getUTF8( ifpDb, NULL, 0, 0,
|
|
FLM_MAX_UINT, NULL, &uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getUTF8( ifpDb, (FLMBYTE *)pvBuffer, uiBufSize, 0,
|
|
FLM_MAX_UINT, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getBinary(
|
|
IF_Db * ifpDb,
|
|
void * pvValue,
|
|
FLMUINT uiByteOffset,
|
|
FLMUINT uiBytesRequested,
|
|
FLMUINT * puiBytesReturned)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
|
|
IF_PosIStream * pIStream = NULL;
|
|
IF_IStream * pDecoderStream = NULL;
|
|
F_NodeBufferIStream bufferIStream;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMUINT uiTmp;
|
|
FLMUINT uiDataType;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If a NULL buffer is passed in, just return the
|
|
// data length
|
|
|
|
if( !pucValue)
|
|
{
|
|
if( RC_BAD( rc = getDataLength( pDb, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiByteOffset <= uiTmp)
|
|
{
|
|
*puiBytesReturned = uiTmp - uiByteOffset;
|
|
}
|
|
else
|
|
{
|
|
*puiBytesReturned = 0;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getIStream( pDb, &bufferIStream, &pIStream, &uiDataType)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiDataType == XFLM_TEXT_TYPE)
|
|
{
|
|
F_AsciiStorageStream asciiStream;
|
|
|
|
if( RC_BAD( rc = asciiStream.open( pIStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = FlmOpenBase64DecoderIStream(
|
|
&asciiStream, &pDecoderStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmReadStorageAsBinary(
|
|
pDecoderStream, (FLMBYTE *)pucValue,
|
|
uiBytesRequested, uiByteOffset, puiBytesReturned)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = flmReadStorageAsBinary(
|
|
pIStream, (FLMBYTE *)pucValue,
|
|
uiBytesRequested, uiByteOffset, puiBytesReturned)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pDecoderStream)
|
|
{
|
|
pDecoderStream->Release();
|
|
}
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getBinary(
|
|
IF_Db * ifpDb,
|
|
F_DynaBuf * pBuffer)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMUINT uiBufSize;
|
|
void * pvBuffer = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pBuffer->truncateData( 0);
|
|
|
|
if( RC_BAD( rc = getBinary( ifpDb, NULL, 0, FLM_MAX_UINT, &uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getBinary( ifpDb, pvBuffer, 0, uiBufSize, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getAttributeValueNumber(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrName,
|
|
FLMUINT64 * pui64Num,
|
|
FLMBOOL * pbNeg)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = checkAttrList()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->getNumber64( pDb, uiAttrName,
|
|
pui64Num, pbNeg)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getAttributeValueText(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
eXFlmTextType eTextType,
|
|
void * pvBuffer,
|
|
FLMUINT uiBufSize,
|
|
FLMUINT * puiCharsReturned,
|
|
FLMUINT * puiBufferBytesUsed)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE * pucStorageData = NULL;
|
|
FLMUINT uiDataType;
|
|
FLMUINT uiDataLength;
|
|
F_AttrItem * pAttrItem;
|
|
IF_PosIStream * pIStream = NULL;
|
|
F_NodeBufferIStream bufferIStream;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = checkAttrList()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pAttrItem = m_pCachedNode->getAttribute( uiAttrName, NULL)) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pAttrItem->m_uiEncDefId)
|
|
{
|
|
pucStorageData = pAttrItem->getAttrDataPtr();
|
|
uiDataLength = pAttrItem->getAttrDataLength();
|
|
uiDataType = pAttrItem->m_uiDataType;
|
|
|
|
if( uiDataType == XFLM_TEXT_TYPE && eTextType == XFLM_UTF8_TEXT)
|
|
{
|
|
const FLMBYTE * pucStart = pucStorageData;
|
|
const FLMBYTE * pucEnd = pucStart + uiDataLength;
|
|
FLMUINT uiCharCount = 0;
|
|
FLMUINT uiStrByteLen = 0;
|
|
|
|
if( pucStart)
|
|
{
|
|
if( RC_BAD( rc = f_decodeSEN( &pucStart, pucEnd, &uiCharCount)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiStrByteLen = (FLMUINT)(pucEnd - pucStart);
|
|
|
|
if( uiBufSize < uiStrByteLen)
|
|
{
|
|
goto SlowDecode;
|
|
}
|
|
|
|
f_memcpy( pvBuffer, pucStart, uiStrByteLen);
|
|
}
|
|
|
|
if( puiCharsReturned)
|
|
{
|
|
*puiCharsReturned = uiCharCount;
|
|
}
|
|
|
|
if( puiBufferBytesUsed)
|
|
{
|
|
*puiBufferBytesUsed = uiStrByteLen;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getIStream( pDb, uiAttrName,
|
|
&bufferIStream, &pIStream, &uiDataType, &uiDataLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
SlowDecode:
|
|
|
|
if( RC_BAD( rc = flmReadStorageAsText(
|
|
pIStream, pucStorageData, uiDataLength, uiDataType, pvBuffer,
|
|
uiBufSize, eTextType, FLM_MAX_UINT, 0, puiCharsReturned,
|
|
puiBufferBytesUsed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getAttributeValueUnicode(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
F_DynaBuf * pBuffer)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiBufSize;
|
|
void * pvBuffer = NULL;
|
|
|
|
pBuffer->truncateData( 0);
|
|
|
|
if( RC_BAD( rc = getAttributeValueUnicode( ifpDb, uiAttrName,
|
|
NULL, 0, NULL, &uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getAttributeValueUnicode( ifpDb, uiAttrName,
|
|
(FLMUNICODE *)pvBuffer, uiBufSize, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getAttributeValueUnicode(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
FLMUNICODE ** ppuzUnicode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiBufSize;
|
|
|
|
if( RC_BAD( rc = getAttributeValueUnicode( ifpDb, uiAttrName,
|
|
NULL, 0, NULL, &uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiBufSize)
|
|
{
|
|
if( RC_BAD( rc = f_alloc( uiBufSize, ppuzUnicode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getAttributeValueUnicode( ifpDb, uiAttrName,
|
|
*ppuzUnicode, uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppuzUnicode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getAttributeValueUTF8(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
FLMBYTE ** ppszValue)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiBufSize;
|
|
|
|
if( RC_BAD( rc = getAttributeValueUTF8( ifpDb, uiAttrName,
|
|
NULL, 0, NULL, &uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiBufSize)
|
|
{
|
|
if( RC_BAD( rc = f_alloc( uiBufSize, ppszValue)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getAttributeValueUTF8( ifpDb, uiAttrName,
|
|
*ppszValue, uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppszValue = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getAttributeValueUTF8(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
F_DynaBuf * pBuffer)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiBufSize;
|
|
void * pvBuffer = NULL;
|
|
|
|
pBuffer->truncateData( 0);
|
|
|
|
if( RC_BAD( rc = getAttributeValueUTF8( ifpDb, uiAttrName,
|
|
NULL, 0, NULL, &uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getAttributeValueUTF8( ifpDb, uiAttrName,
|
|
(FLMBYTE *)pvBuffer, uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getAttributeValueBinary(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
void * pvValue,
|
|
FLMUINT uiBufferSize,
|
|
FLMUINT * puiLength)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = checkAttrList()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->getBinary( pDb, uiAttrName,
|
|
pvValue, uiBufferSize, puiLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getAttributeValueBinary(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
F_DynaBuf * pBuffer)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiBufSize;
|
|
void * pvBuffer = NULL;
|
|
|
|
pBuffer->truncateData( 0);
|
|
|
|
if( RC_BAD( rc = getAttributeValueBinary( ifpDb, uiAttrName, NULL, 0,
|
|
&uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBuffer->allocSpace( uiBufSize, &pvBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getAttributeValueBinary( ifpDb, uiAttrName, pvBuffer,
|
|
uiBufSize, &uiBufSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
ifpDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::setAttributeValueNumber(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
FLMINT64 i64Value,
|
|
FLMUINT64 ui64Value,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pAttribute = NULL;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMBOOL bNeg = FALSE;
|
|
FLMBOOL bIsInIndexDef = FALSE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->attrIsInIndexDef( uiAttrName, &bIsInIndexDef)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsInIndexDef)
|
|
{
|
|
if( RC_BAD( rc = createAttribute( (IF_Db *)pDb, uiAttrName,
|
|
(IF_DOMNode **)&pAttribute)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = pAttribute->setNumber64( pDb, i64Value,
|
|
ui64Value, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( !ui64Value)
|
|
{
|
|
if( i64Value < 0)
|
|
{
|
|
bNeg = TRUE;
|
|
ui64Value = (FLMUINT64)-i64Value;
|
|
}
|
|
else
|
|
{
|
|
ui64Value = (FLMUINT64)i64Value;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->setNumber64( pDb,
|
|
uiAttrName, ui64Value, bNeg, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the value to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
|
|
m_pCachedNode, uiAttrName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
bStartedTrans = FALSE;
|
|
if( RC_BAD( rc = pDb->transCommit()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttribute)
|
|
{
|
|
pAttribute->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::setAttributeValueUnicode(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
const FLMUNICODE * puzValue,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pAttribute = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = createAttribute( (IF_Db *)pDb, uiAttrName,
|
|
(IF_DOMNode **)&pAttribute)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttribute->setUnicode( (IF_Db *)pDb, puzValue, 0,
|
|
TRUE, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
bStartedTrans = FALSE;
|
|
if( RC_BAD( rc = pDb->transCommit()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttribute)
|
|
{
|
|
pAttribute->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::setAttributeValueBinary(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
const void * pvValue,
|
|
FLMUINT uiLength,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pAttribute = NULL;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMBOOL bIsInIndexDef = FALSE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->attrIsInIndexDef( uiAttrName, &bIsInIndexDef)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsInIndexDef)
|
|
{
|
|
if( RC_BAD( rc = createAttribute( (IF_Db *)pDb, uiAttrName,
|
|
(IF_DOMNode **)&pAttribute)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttribute->setBinary(
|
|
(IF_Db *)pDb, (FLMBYTE *)pvValue, uiLength, TRUE, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->setBinary( pDb,
|
|
uiAttrName, pvValue, uiLength, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the value to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
|
|
m_pCachedNode, uiAttrName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
bStartedTrans = FALSE;
|
|
if( RC_BAD( rc = pDb->transCommit()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttribute)
|
|
{
|
|
pAttribute->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::setAttributeValueUTF8(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName,
|
|
const FLMBYTE * pucValue,
|
|
FLMUINT uiLength,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pAttribute = NULL;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMUINT uiNumCharsInBuffer;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMBOOL bIsInIndexDef = FALSE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->attrIsInIndexDef( uiAttrName, &bIsInIndexDef)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsInIndexDef)
|
|
{
|
|
if( RC_BAD( rc = createAttribute( (IF_Db *)pDb, uiAttrName,
|
|
(IF_DOMNode **)&pAttribute)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttribute->setUTF8(
|
|
(IF_Db *)pDb, pucValue, uiLength, TRUE, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = f_getUTF8Length( pucValue, uiLength,
|
|
&uiLength, &uiNumCharsInBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( m_pCachedNode->setUTF8( pDb, uiAttrName, pucValue,
|
|
uiLength, uiNumCharsInBuffer, uiEncDefId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the value to the RFL
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logAttrSetValue( pDb,
|
|
m_pCachedNode, uiAttrName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
bStartedTrans = FALSE;
|
|
if( RC_BAD( rc = pDb->transCommit()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttribute)
|
|
{
|
|
pAttribute->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Delete a node and all of its child/descendant-nodes.
|
|
NOTE: If the cannot-delete bit or read-only bit is set on the node, the delete
|
|
is not allowed. However, the child/descendant-nodes cannot-delete and
|
|
read-only bits will NOT be checked. If a parent node can be deleted,
|
|
then by definition all of its child/descendant nodes can also be deleted.
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::deleteNode(
|
|
IF_Db * ifpDb)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT64 ui64CurNode;
|
|
F_DOMNode * pCurNode = NULL;
|
|
F_DOMNode * pParentNode = NULL;
|
|
F_DOMNode * pTmpNode = NULL;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMBOOL bStartOfUpdate;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiCollection;
|
|
FLMUINT uiFlags = 0;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMUINT64 ui64MyNodeId;
|
|
FLMBOOL bIsIndexed;
|
|
eDomNodeType eNodeType;
|
|
|
|
// Start a transaction if necessary
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiCollection = getCollection();
|
|
eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( uiCollection, getParentId(), &pCurNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DATA_ERROR);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
rc = pCurNode->deleteAttribute( pDb, m_uiAttrNameId);
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// See if the node can be deleted
|
|
|
|
if( getModeFlags() & (FDOM_READ_ONLY | FDOM_CANNOT_DELETE))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DELETE_NOT_ALLOWED);
|
|
goto Exit;
|
|
}
|
|
|
|
if( isRootNode())
|
|
{
|
|
// Set flags to FLM_UPD_INTERNAL_CHANGE to prevent the node
|
|
// from being added to the document list or constraint
|
|
// checking list - no need since we are deleting the root node.
|
|
|
|
uiFlags = FLM_UPD_INTERNAL_CHANGE;
|
|
|
|
// If we are deleting the root node of a document in the dictionary
|
|
// collection, before deleting it, we must allow the dictionary
|
|
// to be updated.
|
|
|
|
if( uiCollection == XFLM_DICT_COLLECTION)
|
|
{
|
|
// Call dictDocumentDone with bDeleting flag set to TRUE.
|
|
|
|
if( RC_BAD( rc = pDb->dictDocumentDone(
|
|
getNodeId(), TRUE, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pDb->m_pDatabase->m_DocumentList.removeNode( uiCollection,
|
|
getNodeId(), 0);
|
|
}
|
|
}
|
|
bMustAbortOnError = TRUE;
|
|
|
|
// Traverse the tree and delete all nodes below and including the
|
|
// node we are starting on.
|
|
|
|
ui64MyNodeId = ui64CurNode = getNodeId();
|
|
bStartOfUpdate = TRUE;
|
|
for (;;)
|
|
{
|
|
if (RC_BAD( rc = pDb->getNode( uiCollection, ui64CurNode, &pCurNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DATA_ERROR);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
// If the current node has children, go to those children
|
|
|
|
if( pCurNode->getLastChildId())
|
|
{
|
|
ui64CurNode = pCurNode->getLastChildId();
|
|
}
|
|
else if( pCurNode->hasAttributes())
|
|
{
|
|
if( pCurNode->getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( pCurNode->m_pCachedNode->m_uiAttrCount);
|
|
|
|
if( RC_BAD( rc = pCurNode->deleteAttributes( pDb, 0, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if (pCurNode->getAnnotationId())
|
|
{
|
|
ui64CurNode = pCurNode->getAnnotationId();
|
|
}
|
|
else
|
|
{
|
|
// Node has no children, no attributes, and no annotations. It is
|
|
// therefore a leaf node that can be purged.
|
|
|
|
FLMUINT64 ui64ParentId;
|
|
FLMBOOL bWasDataNode = FALSE;
|
|
|
|
// Save the node's parent node before purging it. That is the
|
|
// node we want to return to.
|
|
|
|
if( RC_BAD( rc = pCurNode->getParentId( pDb, &ui64ParentId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Update the index
|
|
|
|
if( pCurNode->getNodeType() == DATA_NODE)
|
|
{
|
|
bWasDataNode = TRUE;
|
|
|
|
// Data nodes MUST be children to an element node.
|
|
|
|
flmAssert( ui64ParentId);
|
|
if (RC_BAD( rc = pDb->getNode( uiCollection, ui64ParentId,
|
|
(IF_DOMNode **)&pParentNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = pDb->updateIndexKeys(
|
|
uiCollection, pParentNode, IX_DEL_NODE_VALUE,
|
|
bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = pDb->updateIndexKeys(
|
|
uiCollection, pCurNode, IX_DEL_NODE_VALUE,
|
|
bStartOfUpdate, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartOfUpdate = FALSE;
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if (RC_BAD( rc = pDb->updateIndexKeys(
|
|
uiCollection, pCurNode, IX_UNLINK_NODE,
|
|
bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
flmAssert( pCurNode->getNodeType() != ATTRIBUTE_NODE);
|
|
|
|
if (RC_BAD( rc = pCurNode->unlinkNode( pDb, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->purgeNode( uiCollection, ui64CurNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pCurNode->Release();
|
|
pCurNode = NULL;
|
|
|
|
if( bWasDataNode)
|
|
{
|
|
flmAssert( pParentNode);
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
uiCollection, pParentNode, IX_ADD_NODE_VALUE,
|
|
bStartOfUpdate)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartOfUpdate = FALSE;
|
|
}
|
|
|
|
// Did we just delete the primary target or root node?
|
|
// Do NOT access m_pCachedNode after this point, because it
|
|
// may have been set to NULL by the call to purgeNode.
|
|
|
|
if (ui64CurNode == ui64MyNodeId || !ui64ParentId)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Go back to the parent node.
|
|
|
|
ui64CurNode = ui64ParentId;
|
|
}
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeDelete( pDb, uiCollection, ui64MyNodeId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pTmpNode)
|
|
{
|
|
pTmpNode->Release();
|
|
}
|
|
|
|
if( pCurNode)
|
|
{
|
|
pCurNode->Release();
|
|
}
|
|
|
|
if( pParentNode)
|
|
{
|
|
pParentNode->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::deleteChildren(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiNameId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT64 ui64NextNode;
|
|
F_DOMNode * pCurNode = NULL;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMUINT uiCollection;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
eDomNodeType eNodeType;
|
|
|
|
// Start a transaction if necessary
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiCollection = getCollection();
|
|
eNodeType = getNodeType();
|
|
|
|
// Not supported on attribute nodes
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// See if the node can be deleted
|
|
|
|
if( getModeFlags() & (FDOM_READ_ONLY | FDOM_CANNOT_DELETE))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DELETE_NOT_ALLOWED);
|
|
goto Exit;
|
|
}
|
|
|
|
// Turn of RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Iterate over the children
|
|
|
|
bMustAbortOnError = TRUE;
|
|
ui64NextNode = getFirstChildId();
|
|
|
|
while( ui64NextNode)
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( uiCollection,
|
|
ui64NextNode, XFLM_EXACT, &pCurNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ui64NextNode = pCurNode->getNextSibId();
|
|
|
|
if( !uiNameId || uiNameId == pCurNode->getNameId())
|
|
{
|
|
if( RC_BAD( rc = pCurNode->deleteNode( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeChildrenDelete(
|
|
pDb, uiCollection, getNodeId(), uiNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pCurNode)
|
|
{
|
|
pCurNode->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::_syncFromDb(
|
|
F_Db * pDb)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pDOMNode = this;
|
|
|
|
// If we get to this point, we are going to read the node
|
|
// from the database. This instance of the node should
|
|
// not be dirty.
|
|
|
|
flmAssert( !nodeIsDirty());
|
|
|
|
// Should not have any input streams open on the cached node
|
|
|
|
if( getStreamUseCount())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->retrieveNode( pDb,
|
|
getCollection(), m_pCachedNode->getNodeId(), &pDOMNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_DELETED);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( m_uiAttrNameId)
|
|
{
|
|
if( !m_pCachedNode->m_uiAttrCount ||
|
|
!m_pCachedNode->getAttribute( m_uiAttrNameId, NULL))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_DELETED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getFirstAttribute(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppAttr)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DOMNode * pAttrNode = NULL;
|
|
F_AttrItem * pAttrItem;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = checkAttrList()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pAttrItem = m_pCachedNode->getFirstAttribute()) == NULL)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttrNode->m_pCachedNode = m_pCachedNode;
|
|
m_pCachedNode->incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
pAttrNode->m_uiAttrNameId = pAttrItem->m_uiNameId;
|
|
|
|
if( ifppAttr)
|
|
{
|
|
if( *ifppAttr)
|
|
{
|
|
(*ifppAttr)->Release();
|
|
}
|
|
|
|
*ifppAttr = (IF_DOMNode *)pAttrNode;
|
|
pAttrNode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttrNode)
|
|
{
|
|
pAttrNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getLastAttribute(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppAttr)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DOMNode * pAttrNode = NULL;
|
|
F_AttrItem * pAttrItem;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = checkAttrList()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pAttrItem = m_pCachedNode->getLastAttribute()) == NULL)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttrNode->m_pCachedNode = m_pCachedNode;
|
|
m_pCachedNode->incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
pAttrNode->m_uiAttrNameId = pAttrItem->m_uiNameId;
|
|
|
|
if( ifppAttr)
|
|
{
|
|
if( *ifppAttr)
|
|
{
|
|
(*ifppAttr)->Release();
|
|
}
|
|
|
|
*ifppAttr = (IF_DOMNode *)pAttrNode;
|
|
pAttrNode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttrNode)
|
|
{
|
|
pAttrNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::deleteAttribute(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiAttrName)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
|
|
if( !uiAttrName)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = deleteAttributes( (F_Db *)ifpDb,
|
|
uiAttrName, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::deleteAttributes(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrToDelete,
|
|
FLMUINT uiFlags)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMUINT uiCollection;
|
|
FLMUINT uiAttrName;
|
|
F_DOMNode * pAttrNode = NULL;
|
|
F_AttrItem * pAttrItem;
|
|
FLMUINT uiPos;
|
|
FLMBOOL bIsIndexed;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !m_pCachedNode->m_uiAttrCount)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
uiCollection = getCollection();
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttrNode->m_pCachedNode = m_pCachedNode;
|
|
m_pCachedNode->incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
|
|
for( ;;)
|
|
{
|
|
if( !uiAttrToDelete)
|
|
{
|
|
pAttrItem = m_pCachedNode->getFirstAttribute();
|
|
uiPos = 0;
|
|
}
|
|
else
|
|
{
|
|
if( (pAttrItem = m_pCachedNode->getAttribute( uiAttrToDelete,
|
|
&uiPos)) == NULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( uiAttrToDelete &&
|
|
(pAttrItem->m_uiFlags & (FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DELETE_NOT_ALLOWED);
|
|
goto Exit;
|
|
}
|
|
|
|
uiAttrName = pAttrItem->m_uiNameId;
|
|
pAttrNode->m_uiAttrNameId = uiAttrName;
|
|
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
uiCollection, pAttrNode, IX_DEL_NODE_VALUE,
|
|
TRUE, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
uiCollection, pAttrNode, IX_UNLINK_NODE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Free the attribute
|
|
|
|
if (RC_BAD( rc = m_pCachedNode->freeAttribute( pAttrItem, uiPos)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logAttributeDelete( pDb, uiCollection,
|
|
getNodeId(), uiAttrName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( !m_pCachedNode->m_uiAttrCount)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
bStartedTrans = FALSE;
|
|
if( RC_BAD( rc = pDb->transCommit()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttrNode)
|
|
{
|
|
pAttrNode->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::hasAttribute(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiNameId,
|
|
IF_DOMNode ** ifppAttr)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_DOMNode * pAttrNode = NULL;
|
|
F_AttrItem * pAttrItem;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = checkAttrList()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pAttrItem = m_pCachedNode->getAttribute( uiNameId, NULL)) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( ifppAttr)
|
|
{
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttrNode->m_pCachedNode = m_pCachedNode;
|
|
m_pCachedNode->incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
pAttrNode->m_uiAttrNameId = pAttrItem->m_uiNameId;
|
|
|
|
if( *ifppAttr)
|
|
{
|
|
(*ifppAttr)->Release();
|
|
}
|
|
|
|
*ifppAttr = (IF_DOMNode *)pAttrNode;
|
|
pAttrNode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttrNode)
|
|
{
|
|
pAttrNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::insertChildElm(
|
|
FLMUINT uiChildElmOffset,
|
|
FLMUINT uiChildElmNameId,
|
|
FLMUINT64 ui64ChildElmNodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
NODE_ITEM * pChildElmNode;
|
|
|
|
if( RC_BAD( rc = resizeChildElmList( m_nodeInfo.uiChildElmCount + 1, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Remember, m_nodeInfo.uiChildElmCount has been incremented by
|
|
// resizeChildElmList, so there really isn't anything in the
|
|
// m_nodeInfo.uiChildElmCount - 1 slot.
|
|
|
|
pChildElmNode = &m_pNodeList [ uiChildElmOffset];
|
|
if( m_nodeInfo.uiChildElmCount > 1 &&
|
|
uiChildElmOffset < m_nodeInfo.uiChildElmCount - 1)
|
|
{
|
|
f_memmove( &m_pNodeList [ uiChildElmOffset + 1], pChildElmNode,
|
|
sizeof( NODE_ITEM) * (m_nodeInfo.uiChildElmCount -
|
|
uiChildElmOffset - 1));
|
|
|
|
}
|
|
|
|
pChildElmNode->uiNameId = uiChildElmNameId;
|
|
pChildElmNode->ui64NodeId = ui64ChildElmNodeId;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::createAttribute(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiNameId,
|
|
IF_DOMNode ** ifppAttr)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_AttrElmInfo attrInfo;
|
|
F_DOMNode * pAttr = NULL;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMUINT uiRflToken = 0;
|
|
F_AttrItem * pAttrItem = NULL;
|
|
FLMBOOL bCreatedNewAttr = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Make sure our copy of the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If this isn't an element node, return an error
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
// Force the transaction to abort on error beyond this point
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
// Check the attribute state
|
|
|
|
if( RC_BAD( rc = pDb->checkAndUpdateState(
|
|
ATTRIBUTE_NODE, uiNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Retrieve or create the attribute list node
|
|
|
|
if( !m_pCachedNode->m_uiAttrCount ||
|
|
(pAttrItem = m_pCachedNode->getAttribute( uiNameId, NULL)) == NULL)
|
|
{
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->createAttribute(
|
|
pDb, uiNameId, &pAttrItem)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bCreatedNewAttr = TRUE;
|
|
}
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttr)))
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttr->m_pCachedNode = m_pCachedNode;
|
|
m_pCachedNode->incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
pAttr->m_uiAttrNameId = uiNameId;
|
|
|
|
if( bCreatedNewAttr)
|
|
{
|
|
// Update the element.
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode,
|
|
FLM_UPD_INTERNAL_CHANGE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Update the indexes
|
|
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( getCollection(),
|
|
pAttr, IX_LINK_AND_ADD_NODE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the attribute create
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logAttributeCreate(
|
|
pDb, getCollection(), getNodeId(), uiNameId, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( ifppAttr)
|
|
{
|
|
if( *ifppAttr)
|
|
{
|
|
(*ifppAttr)->Release();
|
|
}
|
|
|
|
*ifppAttr = (IF_DOMNode *)pAttr;
|
|
pAttr = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttr)
|
|
{
|
|
pAttr->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::createNode(
|
|
IF_Db * ifpDb,
|
|
eDomNodeType eNodeType,
|
|
FLMUINT uiNameId,
|
|
eNodeInsertLoc eLocation,
|
|
IF_DOMNode ** ifppNewNode,
|
|
FLMUINT64 * pui64NodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
F_DOMNode * pNewNode = NULL;
|
|
F_CachedNode * pNewCachedNode;
|
|
F_DOMNode * pRefNode = NULL;
|
|
F_DOMNode * pNewParent = NULL;
|
|
FLMUINT uiDataType = XFLM_NODATA_TYPE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
|
|
// Not supported for attributes
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure an update transaction is active
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of this node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Make sure the node type is valid
|
|
|
|
if( eLocation == XFLM_FIRST_CHILD || eLocation == XFLM_LAST_CHILD)
|
|
{
|
|
if( RC_BAD( rc = isChildTypeValid( eNodeType)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( eLocation == XFLM_PREV_SIB || eLocation == XFLM_NEXT_SIB)
|
|
{
|
|
if( eNodeType != ELEMENT_NODE && eNodeType != DATA_NODE &&
|
|
eNodeType != COMMENT_NODE && eNodeType != CDATA_SECTION_NODE &&
|
|
eNodeType != PROCESSING_INSTRUCTION_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// If the user is requesting a specific nodeId, then make sure
|
|
// the node is not already in use.
|
|
|
|
if( pui64NodeId)
|
|
{
|
|
if( *pui64NodeId && (pDb->m_uiFlags & FDB_REBUILDING_DATABASE))
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( getCollection(), *pui64NodeId, &pNewNode)))
|
|
{
|
|
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
else
|
|
{
|
|
// Already in use
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( *pui64NodeId)
|
|
{
|
|
// Set to zero so we don't use it. We will return the
|
|
// new nodeId.
|
|
|
|
*pui64NodeId = 0;
|
|
}
|
|
}
|
|
|
|
// Look at the node's state (checking, etc.) and verify that
|
|
// the node's name ID is valid
|
|
//
|
|
// IMPORTANT NOTE: checkAndUpdateState may change m_pDict if it ends
|
|
// up calling changeItemState
|
|
|
|
if( RC_BAD( rc = pDb->checkAndUpdateState( eNodeType, uiNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Create the new node.
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->createNode( pDb,
|
|
getCollection(),
|
|
(FLMUINT64)(pui64NodeId
|
|
? *pui64NodeId
|
|
: (FLMUINT64)0),
|
|
&pNewNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pNewCachedNode = pNewNode->m_pCachedNode;
|
|
if( eNodeType == DATA_NODE)
|
|
{
|
|
flmAssert( getNodeType() == ELEMENT_NODE);
|
|
uiNameId = getNameId();
|
|
}
|
|
|
|
if( eNodeType == ELEMENT_NODE || eNodeType == DATA_NODE)
|
|
{
|
|
F_AttrElmInfo elmInfo;
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getElement( pDb, uiNameId, &elmInfo)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
uiDataType = elmInfo.m_uiDataType;
|
|
|
|
// Is this a node whose child elements must all be unique?
|
|
|
|
if( eNodeType == ELEMENT_NODE &&
|
|
elmInfo.m_uiFlags & ATTR_ELM_UNIQUE_SUBELMS)
|
|
{
|
|
flmAssert( uiDataType == XFLM_NODATA_TYPE);
|
|
pNewCachedNode->setFlags( FDOM_HAVE_CELM_LIST);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiDataType = XFLM_NODATA_TYPE;
|
|
uiNameId = 0;
|
|
}
|
|
|
|
pNewCachedNode->setNodeType( eNodeType);
|
|
pNewCachedNode->setDocumentId( getDocumentId());
|
|
pNewCachedNode->setDataType( uiDataType);
|
|
|
|
if( uiNameId)
|
|
{
|
|
pNewCachedNode->setNameId( uiNameId);
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pNewCachedNode, FLM_UPD_ADD)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys(
|
|
pNewCachedNode->getCollection(),
|
|
pNewNode, IX_ADD_NODE_VALUE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
switch( eLocation)
|
|
{
|
|
case XFLM_FIRST_CHILD:
|
|
{
|
|
pNewParent = this;
|
|
pNewParent->AddRef();
|
|
|
|
if( getFirstChildId())
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode(
|
|
getCollection(),
|
|
getFirstChildId(), &pRefNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XFLM_LAST_CHILD:
|
|
{
|
|
pNewParent = this;
|
|
pNewParent->AddRef();
|
|
break;
|
|
}
|
|
|
|
case XFLM_PREV_SIB:
|
|
{
|
|
if( !getParentId())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->getNode( getCollection(), getParentId(),
|
|
&pNewParent)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRefNode = this;
|
|
pRefNode->AddRef();
|
|
break;
|
|
}
|
|
|
|
case XFLM_NEXT_SIB:
|
|
{
|
|
if( !getParentId())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->getNode( getCollection(), getParentId(),
|
|
&pNewParent)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNextSibId())
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( getCollection(),
|
|
getNextSibId(), &pRefNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pNewParent->insertBefore( pDb, pNewNode, pRefNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pui64NodeId)
|
|
{
|
|
*pui64NodeId = pNewCachedNode->getNodeId();
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeCreate(
|
|
pDb, pNewNode->getCollection(), getNodeId(),
|
|
eNodeType, uiNameId, eLocation, pNewNode->getNodeId())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ifppNewNode)
|
|
{
|
|
if( *ifppNewNode)
|
|
{
|
|
(*ifppNewNode)->Release();
|
|
}
|
|
|
|
*ifppNewNode = (IF_DOMNode *)pNewNode;
|
|
pNewNode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNewNode)
|
|
{
|
|
pNewNode->Release();
|
|
}
|
|
|
|
if( pRefNode)
|
|
{
|
|
pRefNode->Release();
|
|
}
|
|
|
|
if( pNewParent)
|
|
{
|
|
pNewParent->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::createChildElement(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiNameId,
|
|
eNodeInsertLoc eLocation,
|
|
IF_DOMNode ** ifppNewNode,
|
|
FLMUINT64 * pui64NodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
F_DOMNode * pTmpNode = NULL;
|
|
F_DOMNode * pNewNode = NULL;
|
|
F_CachedNode * pNewCachedNode;
|
|
F_AttrElmInfo elmInfo;
|
|
eDomNodeType eThisNodeType;
|
|
FLMUINT uiCollection;
|
|
FLMUINT uiDataType = XFLM_NODATA_TYPE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMBOOL bIsIndexed;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of this node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the insert location is supported
|
|
|
|
if( eLocation != XFLM_FIRST_CHILD && eLocation != XFLM_LAST_CHILD)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Make sure the node type is valid
|
|
|
|
eThisNodeType = getNodeType();
|
|
|
|
if( eThisNodeType != ELEMENT_NODE && eThisNodeType != DOCUMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
// A document node can only have one element node
|
|
|
|
if( eThisNodeType == DOCUMENT_NODE && getFirstChildId())
|
|
{
|
|
if( RC_BAD( rc = getChild( ifpDb, ELEMENT_NODE,
|
|
(IF_DOMNode **)&pTmpNode)))
|
|
{
|
|
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_HIERARCHY_REQUEST_ERR);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Setup misc. variables
|
|
|
|
uiCollection = getCollection();
|
|
|
|
// If the user is requesting a specific nodeId, then make sure
|
|
// the node is not already in use.
|
|
|
|
if( pui64NodeId)
|
|
{
|
|
if( *pui64NodeId && (pDb->m_uiFlags & FDB_REBUILDING_DATABASE))
|
|
{
|
|
if( RC_OK( rc = pDb->getNode( uiCollection, *pui64NodeId, &pNewNode)))
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
else if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( *pui64NodeId)
|
|
{
|
|
*pui64NodeId = 0;
|
|
}
|
|
}
|
|
|
|
// Check the element's state
|
|
|
|
if( RC_BAD( rc = pDb->checkAndUpdateState( ELEMENT_NODE, uiNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Create the new node.
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->createNode( pDb,
|
|
uiCollection,
|
|
(FLMUINT64)(pui64NodeId
|
|
? *pui64NodeId
|
|
: (FLMUINT64)0),
|
|
&pNewNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pNewCachedNode = pNewNode->m_pCachedNode;
|
|
|
|
// Make sure the parent node (this) can be updated
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Does the parent expect all children to be unique?
|
|
|
|
if( getModeFlags() & FDOM_HAVE_CELM_LIST)
|
|
{
|
|
FLMUINT uiInsertPos;
|
|
|
|
if( m_pCachedNode->findChildElm( uiNameId, &uiInsertPos))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_DUPLICATE_ELEMENT);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->insertChildElm( uiInsertPos,
|
|
uiNameId, pNewCachedNode->getNodeId())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Update the element's state
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getElement( pDb, uiNameId, &elmInfo)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiDataType = elmInfo.m_uiDataType;
|
|
|
|
// Is this a node whose children must all be unique?
|
|
|
|
if( elmInfo.m_uiFlags & ATTR_ELM_UNIQUE_SUBELMS)
|
|
{
|
|
flmAssert( uiDataType == XFLM_NODATA_TYPE);
|
|
pNewCachedNode->setFlags( FDOM_HAVE_CELM_LIST);
|
|
}
|
|
|
|
pNewCachedNode->setNodeType( ELEMENT_NODE);
|
|
pNewCachedNode->setParentId( getNodeId());
|
|
pNewCachedNode->setDocumentId( getDocumentId());
|
|
pNewCachedNode->setDataType( uiDataType);
|
|
pNewCachedNode->setNameId( uiNameId);
|
|
|
|
// Set the sibling pointers
|
|
|
|
if( eLocation == XFLM_LAST_CHILD)
|
|
{
|
|
if( getLastChildId())
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( uiCollection,
|
|
getLastChildId(), &pTmpNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
flmAssert( pTmpNode->getNextSibId() == 0);
|
|
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pTmpNode->setNextSibId( pNewCachedNode->getNodeId());
|
|
pNewCachedNode->setPrevSibId( getLastChildId());
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setFirstChildId( pNewCachedNode->getNodeId());
|
|
}
|
|
|
|
setLastChildId( pNewCachedNode->getNodeId());
|
|
}
|
|
else
|
|
{
|
|
flmAssert( eLocation == XFLM_FIRST_CHILD);
|
|
|
|
if( getFirstChildId())
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode(
|
|
uiCollection, getFirstChildId(), &pTmpNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
flmAssert( pTmpNode->getPrevSibId() == 0);
|
|
|
|
if( RC_BAD( rc = pTmpNode->makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pTmpNode->setPrevSibId( pNewCachedNode->getNodeId());
|
|
pNewCachedNode->setNextSibId( getFirstChildId());
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pTmpNode->m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setLastChildId( pNewCachedNode->getNodeId());
|
|
}
|
|
|
|
setFirstChildId( pNewCachedNode->getNodeId());
|
|
}
|
|
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pNewCachedNode, FLM_UPD_ADD)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
|
|
pNewNode, IX_ADD_NODE_VALUE, TRUE, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bIsIndexed)
|
|
{
|
|
if( RC_BAD( rc = pDb->updateIndexKeys( uiCollection,
|
|
pNewNode, IX_LINK_NODE, FALSE, &bIsIndexed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( pui64NodeId)
|
|
{
|
|
*pui64NodeId = pNewCachedNode->getNodeId();
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeCreate( pDb, uiCollection,
|
|
pNewCachedNode->getParentId(),
|
|
ELEMENT_NODE, uiNameId, XFLM_LAST_CHILD, pNewCachedNode->getNodeId())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ifppNewNode)
|
|
{
|
|
if( *ifppNewNode)
|
|
{
|
|
(*ifppNewNode)->Release();
|
|
}
|
|
|
|
*ifppNewNode = (IF_DOMNode *)pNewNode;
|
|
pNewNode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNewNode)
|
|
{
|
|
pNewNode->Release();
|
|
}
|
|
|
|
if( pTmpNode)
|
|
{
|
|
pTmpNode->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::createAnnotation(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppAnnotation,
|
|
FLMUINT64 * pui64NodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pNode = NULL;
|
|
F_CachedNode * pCachedNode;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_DOMNode ** ppAnnotation = (F_DOMNode **)ifppAnnotation;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure our copy of this node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
// Not supported on attribute nodes
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
// If the node already has an annotation, return an error
|
|
|
|
if( getAnnotationId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_EXISTS);
|
|
goto Exit;
|
|
}
|
|
|
|
// If the user is requesting a specific nodeId, then make sure
|
|
// the node is not already in use.
|
|
|
|
if( pui64NodeId)
|
|
{
|
|
if( *pui64NodeId && (pDb->m_uiFlags & FDB_REBUILDING_DATABASE))
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( getCollection(), *pui64NodeId, &pNode)))
|
|
{
|
|
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
else
|
|
{
|
|
// Already in use
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( *pui64NodeId)
|
|
{
|
|
// Set to zero so we don't use it. We will return the
|
|
// new nodeId.
|
|
*pui64NodeId = 0;
|
|
}
|
|
}
|
|
|
|
// Create the new node.
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->createNode( pDb,
|
|
getCollection(),
|
|
(FLMUINT64)(pui64NodeId
|
|
? *pui64NodeId
|
|
: (FLMUINT64)0),
|
|
&pNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pCachedNode = pNode->m_pCachedNode;
|
|
pCachedNode->setNodeType( ANNOTATION_NODE);
|
|
pCachedNode->setDocumentId( getDocumentId());
|
|
pCachedNode->setParentId( getNodeId());
|
|
pCachedNode->setDataType( XFLM_NODATA_TYPE);
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( pCachedNode, FLM_UPD_ADD)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Link the annotation to this node
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
setAnnotationId( pCachedNode->getNodeId());
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc = pDb->transCommit()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = FALSE;
|
|
}
|
|
|
|
if( pui64NodeId)
|
|
{
|
|
*pui64NodeId = pCachedNode->getNodeId();
|
|
}
|
|
|
|
// Release any node that the passed-in parameter may be
|
|
// pointing at
|
|
|
|
if( *ppAnnotation)
|
|
{
|
|
(*ppAnnotation)->Release();
|
|
}
|
|
|
|
*ppAnnotation = pNode;
|
|
pNode = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
if( bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::hasAnnotation(
|
|
IF_Db * ifpDb,
|
|
FLMBOOL * pbHasAnnotation)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
*pbHasAnnotation = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( (F_Db *)ifpDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getAnnotationId())
|
|
{
|
|
*pbHasAnnotation = TRUE;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getAnnotation(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppAnnotation)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( (F_Db *)ifpDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !getAnnotationId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ifpDb->getNode( getCollection(), getAnnotationId(),
|
|
ifppAnnotation)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getDocumentId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 * pui64DocId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64DocId = m_pCachedNode->getDocumentId();
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getNodeId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 * pui64NodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64NodeId = m_pCachedNode->getNodeId();
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: puiAttrNameId returns 0 if the node isn't an attribute.
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getNodeId(
|
|
F_Db * pDb,
|
|
FLMUINT64 * pui64NodeId,
|
|
FLMUINT * puiAttrNameId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64NodeId = m_pCachedNode->getNodeId();
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
*puiAttrNameId = m_uiAttrNameId;
|
|
}
|
|
else
|
|
{
|
|
*puiAttrNameId = 0;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getParentId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 * pui64ParentId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64ParentId = getParentId();
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: COM version of the getPrevSibId method. This method ensures that
|
|
the DOM node is up-to-date.
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getPrevSibId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 * pui64PrevSibId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64PrevSibId = getPrevSibId();
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Desc: COM version of the getNextSibId method. This method ensures that
|
|
the DOM node is up-to-date.
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getNextSibId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 * pui64NextSibId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64NextSibId = getNextSibId();
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: COM version of the getFirstChildId method. This method ensures that
|
|
the DOM node is up-to-date.
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getFirstChildId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 * pui64FirstChildId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64FirstChildId = getFirstChildId();
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Desc: COM version of the getLastChildId method. This method ensures that
|
|
the DOM node is up-to-date.
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getLastChildId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 * pui64LastChildId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64LastChildId = getLastChildId();
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::isNamespaceDecl(
|
|
IF_Db * ifpDb,
|
|
FLMBOOL * pbIsNamespaceDecl)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*pbIsNamespaceDecl = isNamespaceDecl();
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::hasChildren(
|
|
IF_Db * ifpDb,
|
|
FLMBOOL * pbHasChildren)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( (F_Db *)ifpDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
*pbHasChildren = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*pbHasChildren = getFirstChildId() ? TRUE : FALSE;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getNameId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT * puiNameId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
*puiNameId = m_uiAttrNameId;
|
|
}
|
|
else if( m_pCachedNode)
|
|
{
|
|
*puiNameId = getNameId();
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getEncDefId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT * puiEncDefNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getEncDefId(
|
|
m_uiAttrNameId, puiEncDefNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( m_pCachedNode)
|
|
{
|
|
*puiEncDefNumber = getEncDefId();
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getAnnotationId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT64 * pui64AnnotationId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
*pui64AnnotationId = 0;
|
|
}
|
|
else if( m_pCachedNode)
|
|
{
|
|
*pui64AnnotationId = getAnnotationId();
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::getDataType(
|
|
IF_Db * ifpDb,
|
|
FLMUINT * puiDataType)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getDataType(
|
|
m_uiAttrNameId, puiDataType)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*puiDataType = m_pCachedNode->getDataType();
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getPrefixId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT * puiPrefixId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMUINT uiPrefix = 0;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getPrefixId(
|
|
m_uiAttrNameId, &uiPrefix)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (uiPrefix = m_pCachedNode->getPrefixId()) != 0)
|
|
{
|
|
if( RC_BAD( rc = pDb->m_pDict->getPrefix( uiPrefix, NULL)))
|
|
{
|
|
if( rc != NE_XFLM_BAD_PREFIX)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_XFLM_OK;
|
|
uiPrefix = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
*puiPrefixId = uiPrefix;
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::hasAttributes(
|
|
IF_Db * ifpDb,
|
|
FLMBOOL * pbHasAttrs)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
*pbHasAttrs = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
*pbHasAttrs = m_pCachedNode->m_uiAttrCount ? TRUE : FALSE;
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::hasNextSibling(
|
|
IF_Db * ifpDb,
|
|
FLMBOOL * pbHasNextSibling)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
*pbHasNextSibling = (m_pCachedNode->getNextSibId() &&
|
|
getParentId())
|
|
? TRUE
|
|
: FALSE;
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_DOMNode::hasPreviousSibling(
|
|
IF_Db * ifpDb,
|
|
FLMBOOL * pbHasPreviousSibling)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
*pbHasPreviousSibling = (m_pCachedNode->getPrevSibId() &&
|
|
getParentId())
|
|
? TRUE
|
|
: FALSE;
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getAncestorElement(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiNameId,
|
|
IF_DOMNode ** ifppAncestor)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_DOMNode * pTmpNode = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiCollection;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
pTmpNode = this;
|
|
pTmpNode->AddRef();
|
|
uiCollection = getCollection();
|
|
|
|
while( pTmpNode)
|
|
{
|
|
if( !pTmpNode->getParentId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->getNode(
|
|
uiCollection, pTmpNode->getParentId(), &pTmpNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pTmpNode->getNameId() == uiNameId)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !pTmpNode)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( *ifppAncestor)
|
|
{
|
|
(*ifppAncestor)->Release();
|
|
}
|
|
|
|
*ifppAncestor = pTmpNode;
|
|
pTmpNode = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pTmpNode)
|
|
{
|
|
pTmpNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getDescendantElement(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiNameId,
|
|
IF_DOMNode ** ifppDescendant)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_DOMNode * pContextNode = NULL;
|
|
F_DOMNode * pFoundNode = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiCollection;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pContextNode = this;
|
|
pContextNode->AddRef();
|
|
|
|
uiCollection = getCollection();
|
|
while( pContextNode)
|
|
{
|
|
if( pContextNode->getFirstChildId())
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( uiCollection,
|
|
pContextNode->getFirstChildId(), &pContextNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( pContextNode->getNextSibId())
|
|
{
|
|
Get_Next_Sib:
|
|
|
|
if( pContextNode->getNodeId() == getNodeId())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->getNode( uiCollection,
|
|
pContextNode->getNextSibId(), &pContextNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pContextNode->getNodeId() == getNodeId())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->getNode( uiCollection,
|
|
pContextNode->getParentId(), &pContextNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
goto Get_Next_Sib;
|
|
}
|
|
|
|
if( pContextNode->getNodeType() != ELEMENT_NODE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( pContextNode->getNameId() == uiNameId)
|
|
{
|
|
pFoundNode = pContextNode;
|
|
pFoundNode->AddRef();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( *ifppDescendant)
|
|
{
|
|
(*ifppDescendant)->Release();
|
|
}
|
|
|
|
*ifppDescendant = pFoundNode;
|
|
pFoundNode = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pContextNode)
|
|
{
|
|
pContextNode->Release();
|
|
}
|
|
|
|
if( pFoundNode)
|
|
{
|
|
pFoundNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getDocumentNode(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppDoc)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( isRootNode())
|
|
{
|
|
IF_DOMNode * pTmpNode = *ifppDoc;
|
|
|
|
*ifppDoc = this;
|
|
(*ifppDoc)->AddRef();
|
|
|
|
if( pTmpNode)
|
|
{
|
|
pTmpNode->Release();
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ifpDb->getNode( getCollection(),
|
|
getDocumentId(), ifppDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getParentNode(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppParent)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !getParentId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ifpDb->getNode(
|
|
getCollection(), getParentId(), ifppParent)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getFirstChild(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppChild)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !getFirstChildId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ifpDb->getNode( getCollection(),
|
|
getFirstChildId(), ifppChild)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getLastChild(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppChild)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !getLastChildId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ifpDb->getNode( getCollection(),
|
|
getLastChildId(), ifppChild)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getChild(
|
|
IF_Db * ifpDb,
|
|
eDomNodeType eNodeType,
|
|
IF_DOMNode ** ppChild)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DOMNode * pCurNode = NULL;
|
|
FLMUINT64 ui64NodeId;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// We can do a quick lookup if this node is an element where we are
|
|
// maintaining a child element list.
|
|
|
|
if( eNodeType == ELEMENT_NODE &&
|
|
(getModeFlags() & FDOM_HAVE_CELM_LIST))
|
|
{
|
|
if( getChildElmCount())
|
|
{
|
|
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
|
|
getCollection(), getChildElmNodeId( 0), ppChild)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
ui64NodeId = getFirstChildId();
|
|
|
|
for( ;;)
|
|
{
|
|
if( !ui64NodeId)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
|
|
getCollection(), ui64NodeId, (IF_DOMNode **)&pCurNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pCurNode->getNodeType() == eNodeType)
|
|
{
|
|
if( *ppChild)
|
|
{
|
|
(*ppChild)->Release();
|
|
}
|
|
|
|
*ppChild = pCurNode;
|
|
pCurNode = NULL;
|
|
break;
|
|
}
|
|
|
|
ui64NodeId = pCurNode->getNextSibId();
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pCurNode)
|
|
{
|
|
pCurNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getChildElement(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiNameId,
|
|
IF_DOMNode ** ppChild,
|
|
FLMUINT uiFlags)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DOMNode * pCurNode = NULL;
|
|
FLMUINT64 ui64NodeId;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMUINT uiCollection;
|
|
FLMUINT uiElmPos;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// We can do a quick lookup if this node is an element where we are
|
|
// maintaining a child element list.
|
|
|
|
if( getModeFlags() & FDOM_HAVE_CELM_LIST)
|
|
{
|
|
if( !getChildElmCount())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !findChildElm( uiNameId, &uiElmPos) &&
|
|
(!uiFlags || (uiFlags & XFLM_EXACT) ||
|
|
uiElmPos >= getChildElmCount()))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
// At this point, if we did an exact match, we will be on the node.
|
|
// If we did an inclusive match, we will be either on the node or
|
|
// past it. If we did an exclusive match, we need to determine if
|
|
// we are on the node or past it. If we are on the node, we need
|
|
// to try to move past it, unless we are at the end of the list, in
|
|
// which case we cannot go exclusive.
|
|
|
|
if( uiFlags & XFLM_EXCL)
|
|
{
|
|
// If we found the node, we need to go one past it, if there
|
|
// is one past it to go to. If not, we must return
|
|
// not found.
|
|
|
|
if( getChildElmNameId( uiElmPos) == uiNameId)
|
|
{
|
|
if( uiElmPos == getChildElmCount() - 1)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
uiElmPos++;
|
|
}
|
|
}
|
|
}
|
|
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode( getCollection(),
|
|
getChildElmNodeId( uiElmPos), ppChild)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Cannot set uiFlags for nodes that are not unique-child nodes.
|
|
|
|
if( uiFlags)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_FLAG);
|
|
goto Exit;
|
|
}
|
|
|
|
ui64NodeId = getFirstChildId();
|
|
uiCollection = getCollection();
|
|
for( ;;)
|
|
{
|
|
if( !ui64NodeId)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
|
|
uiCollection, ui64NodeId, (IF_DOMNode **)&pCurNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( pCurNode->getNodeType() == ELEMENT_NODE &&
|
|
pCurNode->getNameId() == uiNameId)
|
|
{
|
|
if( *ppChild)
|
|
{
|
|
(*ppChild)->Release();
|
|
}
|
|
|
|
*ppChild = pCurNode;
|
|
pCurNode = NULL;
|
|
break;
|
|
}
|
|
|
|
ui64NodeId = pCurNode->getNextSibId();
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pCurNode)
|
|
{
|
|
pCurNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getSiblingElement(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiNameId,
|
|
FLMBOOL bNext,
|
|
IF_DOMNode ** ppSibling)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DOMNode * pCurNode = NULL;
|
|
FLMUINT64 ui64NodeId;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMUINT uiCollection;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bNext)
|
|
{
|
|
ui64NodeId = getNextSibId();
|
|
}
|
|
else
|
|
{
|
|
ui64NodeId = getPrevSibId();
|
|
}
|
|
|
|
uiCollection = getCollection();
|
|
for( ;;)
|
|
{
|
|
if( !ui64NodeId)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ((IF_Db *)pDb)->getNode(
|
|
uiCollection, ui64NodeId, (IF_DOMNode **)&pCurNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pCurNode->getNodeType() == ELEMENT_NODE &&
|
|
pCurNode->getNameId() == uiNameId)
|
|
{
|
|
if( *ppSibling)
|
|
{
|
|
(*ppSibling)->Release();
|
|
}
|
|
|
|
*ppSibling = pCurNode;
|
|
pCurNode = NULL;
|
|
break;
|
|
}
|
|
|
|
if( bNext)
|
|
{
|
|
ui64NodeId = pCurNode->getNextSibId();
|
|
}
|
|
else
|
|
{
|
|
ui64NodeId = pCurNode->getPrevSibId();
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pCurNode)
|
|
{
|
|
pCurNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getPreviousSibling(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppSib)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
if( !(*ifppSib))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->getPrevSiblingNode(
|
|
m_uiAttrNameId, ifppSib)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !getPrevSibId() || !getParentId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ifpDb->getNode(
|
|
getCollection(), getPrevSibId(), ifppSib)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getNextSibling(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppSib)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( getNodeType() == ATTRIBUTE_NODE)
|
|
{
|
|
if( !(*ifppSib))
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pCachedNode->getNextSiblingNode(
|
|
m_uiAttrNameId, ifppSib)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !getNextSibId() || !getParentId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ifpDb->getNode( getCollection(),
|
|
getNextSibId(), ifppSib)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getPreviousDocument(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppDoc)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DOMNode * pNode = NULL;
|
|
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
|
|
FLMUINT uiKeyLen;
|
|
FLMUINT64 ui64StartDocId;
|
|
FLMUINT64 ui64DocumentId;
|
|
FLMBOOL bNeg;
|
|
FLMUINT uiBytesProcessed;
|
|
F_Btree * pBTree = NULL;
|
|
FLMUINT uiCollection;
|
|
F_COLLECTION * pCollection;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiCollection = getCollection();
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
if( rc != NE_XFLM_DOM_NODE_DELETED)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pBTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBTree->btOpen( pDb, &pCollection->lfInfo, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ui64DocumentId = ui64StartDocId = getDocumentId();
|
|
uiKeyLen = sizeof( ucKey);
|
|
if( RC_BAD( rc = flmNumber64ToStorage( ui64StartDocId, &uiKeyLen,
|
|
ucKey, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBTree->btLocateEntry(
|
|
ucKey, sizeof( ucKey), &uiKeyLen, XFLM_INCL)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
// Need to go to the previous node.
|
|
|
|
if( RC_BAD( rc = pBTree->btPrevEntry( ucKey, uiKeyLen, &uiKeyLen)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_BOF_HIT)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmCollation2Number( uiKeyLen, ucKey,
|
|
&ui64DocumentId, &bNeg, &uiBytesProcessed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->getNode( uiCollection, ui64DocumentId, &pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
|
|
// Better be able to find the node at this point!
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// If the node is a root node, we have a document we can
|
|
// process.
|
|
|
|
if( pNode->isRootNode() && pNode->getNodeId() < ui64StartDocId)
|
|
{
|
|
if( *ifppDoc)
|
|
{
|
|
(*ifppDoc)->Release();
|
|
}
|
|
|
|
// Just use the reference on pNode for *ifppDoc
|
|
|
|
*ifppDoc = pNode;
|
|
pNode = NULL;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we are not at the root node of the document,
|
|
// jump to the root.
|
|
|
|
if( !isRootNode())
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( uiCollection, getDocumentId(), &pNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNode = this;
|
|
pNode->AddRef();
|
|
}
|
|
|
|
if( !pNode->getPrevSibId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ifpDb->getNode( uiCollection,
|
|
pNode->getPrevSibId(), ifppDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( pBTree)
|
|
{
|
|
pBTree->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getNextDocument(
|
|
IF_Db * ifpDb,
|
|
IF_DOMNode ** ifppDoc)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DOMNode * pNode = NULL;
|
|
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
|
|
FLMUINT uiKeyLen;
|
|
FLMUINT64 ui64DocumentId;
|
|
FLMBOOL bNeg;
|
|
FLMUINT uiBytesProcessed;
|
|
F_Btree * pBTree = NULL;
|
|
FLMUINT uiCollection;
|
|
F_COLLECTION * pCollection;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiCollection = getCollection();
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
if( rc != NE_XFLM_DOM_NODE_DELETED)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pBTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBTree->btOpen( pDb, &pCollection->lfInfo, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
ui64DocumentId = getDocumentId();
|
|
uiKeyLen = sizeof( ucKey);
|
|
if( RC_BAD( rc = flmNumber64ToStorage( ui64DocumentId, &uiKeyLen,
|
|
ucKey, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBTree->btLocateEntry(
|
|
ucKey, sizeof( ucKey), &uiKeyLen, XFLM_EXCL)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
if( RC_BAD( rc = flmCollation2Number( uiKeyLen, ucKey,
|
|
&ui64DocumentId, &bNeg, &uiBytesProcessed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->getNode(
|
|
uiCollection, ui64DocumentId, &pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
|
|
// Better be able to find the node at this point!
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// If the node is a root node, we have a document we can
|
|
// process.
|
|
|
|
if( pNode->isRootNode())
|
|
{
|
|
if( *ifppDoc)
|
|
{
|
|
(*ifppDoc)->Release();
|
|
}
|
|
|
|
// Just use the reference on pNode for *ifppDoc
|
|
|
|
*ifppDoc = pNode;
|
|
pNode = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
// Need to go to the next node.
|
|
|
|
if( RC_BAD( rc = pBTree->btNextEntry( ucKey, uiKeyLen, &uiKeyLen)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
}
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we are not at the root node of the document,
|
|
// jump to the root.
|
|
|
|
if( !isRootNode())
|
|
{
|
|
if( RC_BAD( rc = pDb->getNode( uiCollection, getDocumentId(), &pNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNode = this;
|
|
pNode->AddRef();
|
|
}
|
|
|
|
if( !pNode->getNextSibId())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = ifpDb->getNode(
|
|
uiCollection, getNextSibId(), ifppDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( pBTree)
|
|
{
|
|
pBTree->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE flmReadStorageAsText(
|
|
IF_IStream * pIStream,
|
|
FLMBYTE * pucStorageData,
|
|
FLMUINT uiDataLen,
|
|
FLMUINT uiDataType,
|
|
void * pvBuffer,
|
|
FLMUINT uiBufLen,
|
|
eXFlmTextType eTextType,
|
|
FLMUINT uiMaxCharsToRead,
|
|
FLMUINT uiCharOffset,
|
|
FLMUINT * puiCharsRead,
|
|
FLMUINT * puiBufferBytesUsed)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE ucByte;
|
|
FLMUINT uiCharsDecoded = 0;
|
|
FLMUINT uiSENLen;
|
|
FLMUINT uiNumChars;
|
|
FLMUINT uiCharsOutput = 0;
|
|
FLMUNICODE * puzOutBuf = NULL;
|
|
FLMBYTE * pszOutBuf = NULL;
|
|
void * pvEnd = ((char *)pvBuffer) + uiBufLen;
|
|
const FLMBYTE * pucTmp;
|
|
FLMUINT uiLen;
|
|
FLMBYTE ucSENBuf[ 16];
|
|
FLMBYTE ucConvBuf[ 64];
|
|
FLMUINT uiLastUTFLen = 0;
|
|
IF_IStream * pStream = pIStream;
|
|
IF_BufferIStream * pConvStream = NULL;
|
|
F_BinaryToTextStream binaryToTextStream;
|
|
|
|
// If the value is a number, convert to text
|
|
|
|
if( uiDataType == XFLM_NUMBER_TYPE)
|
|
{
|
|
FLMBYTE ucNumBuf[ FLM_MAX_NUM_BUF_SIZE];
|
|
FLMUINT uiNumBufLen;
|
|
|
|
// Read the entire number into the temporary buffer.
|
|
// NOTE: Numbers are not encoded with a length. It
|
|
// is expected that the number of bytes remaining
|
|
// in the stream will be equal to the exact number of
|
|
// bytes representing the number. If this is not the case,
|
|
// either a corruption error or an incorrect value will
|
|
// be returned.
|
|
|
|
uiNumBufLen = sizeof( ucNumBuf);
|
|
|
|
if( pStream)
|
|
{
|
|
if( RC_BAD( rc = pStream->read( (char *)ucNumBuf,
|
|
uiNumBufLen, &uiNumBufLen)))
|
|
{
|
|
if( rc != NE_XFLM_EOF_HIT)
|
|
{
|
|
goto Exit;
|
|
}
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
f_memcpy( ucNumBuf, pucStorageData, f_max( uiNumBufLen, uiDataLen));
|
|
}
|
|
|
|
// Convert the storage number to storage text
|
|
|
|
uiDataLen = sizeof( ucConvBuf);
|
|
if( RC_BAD( rc = flmStorageNum2StorageText( ucNumBuf, uiNumBufLen,
|
|
ucConvBuf, &uiDataLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmAllocBufferIStream( &pConvStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pConvStream->open( (const char *)ucConvBuf, uiDataLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pStream = pConvStream;
|
|
pucStorageData = NULL;
|
|
}
|
|
else if( uiDataType == XFLM_BINARY_TYPE)
|
|
{
|
|
if( !pStream)
|
|
{
|
|
if( RC_BAD( rc = FlmAllocBufferIStream( &pConvStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pConvStream->open(
|
|
(const char *)pucStorageData, uiDataLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pStream = pConvStream;
|
|
}
|
|
|
|
if( RC_BAD( rc = binaryToTextStream.open( pStream,
|
|
uiDataLen, &uiDataLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pStream = &binaryToTextStream;
|
|
pucStorageData = NULL;
|
|
}
|
|
else if( uiDataType == XFLM_NODATA_TYPE)
|
|
{
|
|
goto Empty_String;
|
|
}
|
|
else if( uiDataType != XFLM_TEXT_TYPE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
|
|
// Determine the SEN length
|
|
|
|
if( pStream)
|
|
{
|
|
uiLen = 1;
|
|
if( RC_BAD( rc = pStream->read( (char *)&ucSENBuf[ 0], uiLen, &uiLen)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
Empty_String:
|
|
rc = NE_XFLM_OK;
|
|
if( eTextType == XFLM_UTF8_TEXT)
|
|
{
|
|
if( pvBuffer)
|
|
{
|
|
*((FLMBYTE *)pvBuffer) = 0;
|
|
}
|
|
if( puiBufferBytesUsed)
|
|
{
|
|
*puiBufferBytesUsed = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flmAssert( eTextType == XFLM_UNICODE_TEXT);
|
|
if( pvBuffer)
|
|
{
|
|
*((FLMUNICODE *)pvBuffer) = 0;
|
|
}
|
|
if( puiBufferBytesUsed)
|
|
{
|
|
*puiBufferBytesUsed = sizeof( FLMUNICODE);
|
|
}
|
|
}
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiDataLen -= uiLen;
|
|
}
|
|
else
|
|
{
|
|
if( !uiDataLen)
|
|
{
|
|
goto Empty_String;
|
|
}
|
|
|
|
ucSENBuf[ 0] = *pucStorageData++;
|
|
uiDataLen--;
|
|
}
|
|
|
|
if( (uiSENLen = f_getSENLength( ucSENBuf[ 0])) > 1)
|
|
{
|
|
uiLen = uiSENLen - 1;
|
|
|
|
if( pStream)
|
|
{
|
|
if( RC_BAD( rc = pStream->read(
|
|
(char *)&ucSENBuf[ 1], uiLen, &uiLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( uiDataLen < uiLen)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_EOF_HIT);
|
|
goto Exit;
|
|
}
|
|
|
|
f_memcpy( &ucSENBuf[ 1], pucStorageData, uiLen);
|
|
pucStorageData += uiLen;
|
|
}
|
|
|
|
uiDataLen -= uiLen;
|
|
}
|
|
|
|
pucTmp = &ucSENBuf[ 0];
|
|
if( RC_BAD( rc = f_decodeSEN(
|
|
&pucTmp, &ucSENBuf[ uiSENLen], &uiNumChars)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If only a length is needed (number of bytes), we can
|
|
// return that without parsing the string
|
|
|
|
if( !pvBuffer)
|
|
{
|
|
uiCharsOutput = uiCharOffset >= uiNumChars
|
|
? 0
|
|
: uiNumChars - uiCharOffset;
|
|
|
|
if( puiBufferBytesUsed)
|
|
{
|
|
if( eTextType == XFLM_UNICODE_TEXT)
|
|
{
|
|
*puiBufferBytesUsed = (uiCharsOutput + 1) * sizeof( FLMUNICODE);
|
|
}
|
|
else // UTF-8
|
|
{
|
|
*puiBufferBytesUsed = uiDataLen;
|
|
}
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( eTextType == XFLM_UTF8_TEXT)
|
|
{
|
|
if( !uiBufLen)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
pszOutBuf = (FLMBYTE *)pvBuffer;
|
|
}
|
|
else
|
|
{
|
|
flmAssert( eTextType == XFLM_UNICODE_TEXT);
|
|
if( uiBufLen < sizeof( FLMUNICODE))
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
puzOutBuf = (FLMUNICODE *)pvBuffer;
|
|
}
|
|
|
|
// If we have a zero-length string, jump to exit.
|
|
|
|
if( !uiNumChars)
|
|
{
|
|
// Read the null terminator
|
|
|
|
if( pStream)
|
|
{
|
|
uiLen = 1;
|
|
if( RC_BAD( rc = pStream->read( (char *)&ucByte, uiLen, &uiLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !uiDataLen)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
ucByte = *pucStorageData++;
|
|
uiDataLen--;
|
|
}
|
|
|
|
if( ucByte != 0)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
goto Empty_String;
|
|
}
|
|
|
|
// Parse through the string, outputting data to the buffer as we go.
|
|
|
|
uiCharsDecoded = 0;
|
|
if( eTextType == XFLM_UNICODE_TEXT)
|
|
{
|
|
FLMUNICODE uChar;
|
|
|
|
while( uiCharsOutput < uiMaxCharsToRead)
|
|
{
|
|
if( pStream)
|
|
{
|
|
if( RC_BAD( rc = f_readUTF8CharAsUnicode( pStream, &uChar)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
Unicode_EOF_Hit:
|
|
if( uiCharsDecoded != uiNumChars)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_XFLM_OK;
|
|
break;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMBYTE ucTmpUni[ 3];
|
|
|
|
if( !uiDataLen)
|
|
{
|
|
goto Unicode_EOF_Hit;
|
|
}
|
|
|
|
ucTmpUni[ 0] = *pucStorageData++;
|
|
uiDataLen--;
|
|
|
|
if( ucTmpUni[ 0] <= 0x7F)
|
|
{
|
|
if( !ucTmpUni[ 0])
|
|
{
|
|
goto Unicode_EOF_Hit;
|
|
}
|
|
|
|
uChar = (FLMUNICODE)ucTmpUni[ 0];
|
|
}
|
|
else
|
|
{
|
|
if( !uiDataLen)
|
|
{
|
|
goto Unicode_EOF_Hit;
|
|
}
|
|
|
|
ucTmpUni[ 1] = *pucStorageData++;
|
|
uiDataLen--;
|
|
|
|
if( (ucTmpUni[ 1] >> 6) != 0x02)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_UTF8);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (ucTmpUni[ 0] >> 5) == 0x06)
|
|
{
|
|
uChar = ((FLMUNICODE)( ucTmpUni[ 0] - 0xC0) << 6) +
|
|
(FLMUNICODE)(ucTmpUni[ 1] - 0x80);
|
|
}
|
|
else
|
|
{
|
|
if( !uiDataLen)
|
|
{
|
|
goto Unicode_EOF_Hit;
|
|
}
|
|
|
|
ucTmpUni[ 2] = *pucStorageData++;
|
|
uiDataLen--;
|
|
|
|
if( (ucTmpUni[ 0] >> 4) != 0x0E ||
|
|
(ucTmpUni[ 2] >> 6) != 0x02)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_UTF8);
|
|
goto Exit;
|
|
}
|
|
|
|
uChar = ((FLMUNICODE)(ucTmpUni[ 0] - 0xE0) << 12) +
|
|
((FLMUNICODE)(ucTmpUni[ 1] - 0x80) << 6) +
|
|
(FLMUNICODE)(ucTmpUni[ 2] - 0x80);
|
|
}
|
|
}
|
|
}
|
|
|
|
if( ++uiCharsDecoded > uiNumChars)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiCharOffset)
|
|
{
|
|
uiCharOffset--;
|
|
continue;
|
|
}
|
|
|
|
if( puzOutBuf)
|
|
{
|
|
if( puzOutBuf + 1 >= pvEnd)
|
|
{
|
|
goto Overflow_Error;
|
|
}
|
|
|
|
*puzOutBuf++ = uChar;
|
|
uiCharsOutput++;
|
|
}
|
|
else
|
|
{
|
|
if( uChar <= 0xFF)
|
|
{
|
|
if( pszOutBuf + 1 >= pvEnd)
|
|
{
|
|
goto Overflow_Error;
|
|
}
|
|
*pszOutBuf++ = f_tonative( (FLMBYTE)uChar);
|
|
uiCharsOutput++;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_ILLEGAL);
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // UTF-8
|
|
{
|
|
flmAssert( eTextType == XFLM_UTF8_TEXT);
|
|
while( uiCharsOutput < uiMaxCharsToRead)
|
|
{
|
|
if( (uiLen = ((FLMBYTE *)pvEnd) - pszOutBuf) == 0)
|
|
{
|
|
rc = RC_SET( NE_XFLM_CONV_DEST_OVERFLOW);
|
|
goto Overflow_Error;
|
|
}
|
|
|
|
if( pStream)
|
|
{
|
|
if( RC_BAD( rc = f_readUTF8CharAsUTF8(
|
|
pStream, pszOutBuf, &uiLen)))
|
|
{
|
|
if( rc == NE_XFLM_CONV_DEST_OVERFLOW)
|
|
{
|
|
goto Overflow_Error;
|
|
}
|
|
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
UTF8_EOF_Hit:
|
|
if( uiCharsDecoded != uiNumChars)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
rc = NE_XFLM_OK;
|
|
break;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !uiDataLen)
|
|
{
|
|
goto UTF8_EOF_Hit;
|
|
}
|
|
|
|
pszOutBuf[ 0] = *pucStorageData++;
|
|
uiDataLen--;
|
|
|
|
if( pszOutBuf[ 0] <= 0x7F)
|
|
{
|
|
if( !pszOutBuf[ 0])
|
|
{
|
|
goto UTF8_EOF_Hit;
|
|
}
|
|
|
|
uiLen = 1;
|
|
}
|
|
else
|
|
{
|
|
if( uiLen < 2)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
|
|
goto Overflow_Error;
|
|
}
|
|
|
|
if( !uiDataLen)
|
|
{
|
|
goto UTF8_EOF_Hit;
|
|
}
|
|
|
|
pszOutBuf[ 1] = *pucStorageData++;
|
|
uiDataLen--;
|
|
|
|
if( (pszOutBuf[ 1] >> 6) != 0x02)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_UTF8);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pszOutBuf[ 0] >> 5) == 0x06)
|
|
{
|
|
uiLen = 2;
|
|
}
|
|
else
|
|
{
|
|
if( uiLen < 3)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
|
|
goto Overflow_Error;
|
|
}
|
|
|
|
if( !uiDataLen)
|
|
{
|
|
goto UTF8_EOF_Hit;
|
|
}
|
|
|
|
pszOutBuf[ 2] = *pucStorageData++;
|
|
uiDataLen--;
|
|
|
|
if( (pszOutBuf[ 0] >> 4) != 0x0E ||
|
|
(pszOutBuf[ 2] >> 6) != 0x02)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_UTF8);
|
|
goto Exit;
|
|
}
|
|
|
|
uiLen = 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( ++uiCharsDecoded > uiNumChars)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiCharOffset)
|
|
{
|
|
uiCharOffset--;
|
|
continue;
|
|
}
|
|
|
|
if( pszOutBuf + uiLen >= pvEnd)
|
|
{
|
|
goto Overflow_Error;
|
|
}
|
|
|
|
pszOutBuf += uiLen;
|
|
uiLastUTFLen = uiLen;
|
|
uiCharsOutput++;
|
|
}
|
|
}
|
|
|
|
// There is room for the 0 terminating character, but we
|
|
// will not increment the return length, but we will output the
|
|
// number of buffer bytes used
|
|
|
|
if( eTextType == XFLM_UTF8_TEXT && pszOutBuf < pvEnd)
|
|
{
|
|
*pszOutBuf = 0;
|
|
if( puiBufferBytesUsed)
|
|
{
|
|
*puiBufferBytesUsed = (FLMUINT)(pszOutBuf - (FLMBYTE *)pvBuffer) + 1;
|
|
}
|
|
}
|
|
else if( eTextType == XFLM_UNICODE_TEXT && &puzOutBuf[ 1] <= pvEnd)
|
|
{
|
|
*puzOutBuf = 0;
|
|
if( puiBufferBytesUsed)
|
|
{
|
|
*puiBufferBytesUsed = (FLMUINT)((FLMBYTE *)puzOutBuf -
|
|
(FLMBYTE *)pvBuffer) + sizeof( FLMUNICODE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Overflow_Error:
|
|
|
|
if( uiCharsOutput)
|
|
{
|
|
uiCharsOutput--;
|
|
if( puzOutBuf)
|
|
{
|
|
*(puzOutBuf - 1) = 0;
|
|
if( puiBufferBytesUsed)
|
|
{
|
|
*puiBufferBytesUsed = (FLMUINT)((FLMBYTE *)puzOutBuf -
|
|
(FLMBYTE *)pvBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszOutBuf -= uiLastUTFLen;
|
|
*pszOutBuf = 0;
|
|
if( puiBufferBytesUsed)
|
|
{
|
|
*puiBufferBytesUsed = (FLMUINT)(pszOutBuf -
|
|
(FLMBYTE *)pvBuffer) + 1;
|
|
}
|
|
}
|
|
}
|
|
else if( puiBufferBytesUsed)
|
|
{
|
|
*puiBufferBytesUsed = 0;
|
|
}
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pConvStream)
|
|
{
|
|
pConvStream->Release();
|
|
}
|
|
|
|
if( puiCharsRead)
|
|
{
|
|
*puiCharsRead = uiCharsOutput;
|
|
}
|
|
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE flmReadStorageAsBinary(
|
|
IF_IStream * pIStream,
|
|
void * pvBuffer,
|
|
FLMUINT uiBufLen,
|
|
FLMUINT uiByteOffset,
|
|
FLMUINT * puiBytesRead)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
|
|
|
|
// Position to the requested offset
|
|
|
|
if( uiByteOffset)
|
|
{
|
|
if( RC_BAD( rc = pIStream->read(
|
|
NULL, uiByteOffset, &uiByteOffset)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Read the requested bytes
|
|
|
|
rc = pIStream->read( pucBuffer, uiBufLen, &uiBufLen);
|
|
|
|
if( puiBytesRead)
|
|
{
|
|
*puiBytesRead = uiBufLen;
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE flmReadStorageAsNumber(
|
|
IF_IStream * pIStream,
|
|
FLMUINT uiDataType,
|
|
FLMUINT64 * pui64Number,
|
|
FLMBOOL * pbNeg)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bNeg = FALSE;
|
|
FLMUINT64 ui64Num = 0;
|
|
|
|
switch( uiDataType)
|
|
{
|
|
case XFLM_NUMBER_TYPE :
|
|
{
|
|
FLMBYTE ucNumBuf[ FLM_MAX_NUM_BUF_SIZE];
|
|
FLMUINT uiNumBufLen;
|
|
|
|
// Read the entire number into the temporary buffer.
|
|
// NOTE: Numbers are not encoded with a length. It
|
|
// is expected that the number of bytes remaining
|
|
// in the stream will be equal to the exact number of
|
|
// bytes representing the number. If this is not the case,
|
|
// either a corruption error or an incorrect value will
|
|
// be returned.
|
|
|
|
uiNumBufLen = sizeof( ucNumBuf);
|
|
if( RC_BAD( rc = pIStream->read(
|
|
(char *)ucNumBuf, uiNumBufLen, &uiNumBufLen)))
|
|
{
|
|
if( rc != NE_XFLM_EOF_HIT)
|
|
{
|
|
goto Exit;
|
|
}
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmStorageNumberToNumber(
|
|
ucNumBuf, uiNumBufLen, &ui64Num, &bNeg)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XFLM_TEXT_TYPE :
|
|
{
|
|
FLMUNICODE uChar;
|
|
FLMUINT uiLoop;
|
|
FLMBOOL bHex = FALSE;
|
|
FLMUINT uiIncrAmount = 0;
|
|
|
|
// Skip the character count
|
|
|
|
if( RC_BAD( rc = f_readSEN64( pIStream, NULL, NULL)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
// Empty string
|
|
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
for( uiLoop = 0;; uiLoop++)
|
|
{
|
|
if( RC_BAD( rc = f_readUTF8CharAsUnicode(
|
|
pIStream, &uChar)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( uChar >= FLM_UNICODE_0 && uChar <= FLM_UNICODE_9)
|
|
{
|
|
uiIncrAmount = (FLMUINT)(uChar - FLM_UNICODE_0);
|
|
}
|
|
else if( uChar >= FLM_UNICODE_A && uChar <= FLM_UNICODE_F)
|
|
{
|
|
if( bHex)
|
|
{
|
|
uiIncrAmount = (FLMUINT)(uChar - FLM_UNICODE_A + 10);
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( uChar >= FLM_UNICODE_a && uChar <= FLM_UNICODE_f)
|
|
{
|
|
if( bHex)
|
|
{
|
|
uiIncrAmount = (FLMUINT)(uChar - FLM_UNICODE_a + 10);
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( uChar == FLM_UNICODE_X || uChar == FLM_UNICODE_x)
|
|
{
|
|
if( !ui64Num && !bHex)
|
|
{
|
|
bHex = TRUE;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( uChar == FLM_UNICODE_HYPHEN && !uiLoop)
|
|
{
|
|
bNeg = TRUE;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !bHex)
|
|
{
|
|
if( ui64Num > (~(FLMUINT64)0) / 10)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
ui64Num *= (FLMUINT64)10;
|
|
}
|
|
else
|
|
{
|
|
if( ui64Num > (~(FLMUINT64)0) / 16)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
ui64Num *= (FLMUINT64)16;
|
|
}
|
|
|
|
if( ui64Num > (~(FLMUINT64)0) - (FLMUINT64)uiIncrAmount)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_NUM_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
ui64Num += (FLMUINT64)uiIncrAmount;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default :
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_BAD_DIGIT);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
*pui64Number = ui64Num;
|
|
*pbNeg = bNeg;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE flmReadLine(
|
|
IF_IStream * pIStream,
|
|
FLMBYTE * pszBuffer,
|
|
FLMUINT * puiSize)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiMaxBytes = *puiSize;
|
|
FLMUINT uiOffset = 0;
|
|
FLMBYTE ucByte;
|
|
|
|
*puiSize = 0;
|
|
|
|
for( ;;)
|
|
{
|
|
if( RC_BAD( rc = pIStream->read( (char *)&ucByte, 1, NULL)))
|
|
{
|
|
if( rc == NE_FLM_IO_END_OF_FILE)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
break;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( ucByte == 0x0A || ucByte == 0x0D)
|
|
{
|
|
if( uiOffset)
|
|
{
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if( (uiOffset + 1) == uiMaxBytes)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BUFFER_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
pszBuffer[ uiOffset++] = (char)ucByte;
|
|
}
|
|
}
|
|
|
|
pszBuffer[ uiOffset] = 0;
|
|
*puiSize = uiOffset;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_BTreeIStream::open(
|
|
F_Db * pDb,
|
|
FLMUINT uiCollection,
|
|
FLMUINT64 ui64NodeId,
|
|
FLMUINT32 ui32BlkAddr,
|
|
FLMUINT uiOffsetIndex)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_COLLECTION * pCollection;
|
|
F_Dict * pDict = pDb->m_pDict;
|
|
F_Btree * pBTree = NULL;
|
|
|
|
if( RC_BAD( rc = pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pBTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set up the btree object
|
|
|
|
if( RC_BAD( rc = pBTree->btOpen( pDb, &pCollection->lfInfo, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = open( pDb, pBTree, XFLM_EXACT, uiCollection, ui64NodeId,
|
|
ui32BlkAddr, uiOffsetIndex)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pBTree = NULL;
|
|
m_bReleaseBTree = TRUE;
|
|
|
|
Exit:
|
|
|
|
if( pBTree)
|
|
{
|
|
gv_XFlmSysData.pBtPool->btpReturnBtree( &pBTree);
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
close();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_BTreeIStream::open(
|
|
F_Db * pDb,
|
|
F_Btree * pBTree,
|
|
FLMUINT uiFlags,
|
|
FLMUINT uiCollection,
|
|
FLMUINT64 ui64NodeId,
|
|
FLMUINT32 ui32BlkAddr,
|
|
FLMUINT uiOffsetIndex)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
|
|
flmAssert( !m_pBTree);
|
|
|
|
m_pDb = pDb;
|
|
m_uiCollection = uiCollection;
|
|
m_pBTree = pBTree;
|
|
|
|
// Save the key and key length
|
|
|
|
m_uiKeyLength = sizeof( m_ucKey);
|
|
if( RC_BAD( rc = flmNumber64ToStorage( ui64NodeId, &m_uiKeyLength,
|
|
m_ucKey, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_ui32BlkAddr = ui32BlkAddr;
|
|
m_uiOffsetIndex = uiOffsetIndex;
|
|
|
|
if( RC_BAD( rc = m_pBTree->btLocateEntry(
|
|
m_ucKey, sizeof( m_ucKey), &m_uiKeyLength, uiFlags,
|
|
NULL, &m_uiStreamSize, &m_ui32BlkAddr, &m_uiOffsetIndex)))
|
|
{
|
|
if( rc == NE_XFLM_NOT_FOUND)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiFlags == XFLM_EXACT)
|
|
{
|
|
m_ui64NodeId = ui64NodeId;
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = flmCollation2Number( m_uiKeyLength, m_ucKey,
|
|
&m_ui64NodeId, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
close();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_BTreeIStream::positionTo(
|
|
FLMUINT64 ui64Position)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
|
|
if( ui64Position >= m_uiBufferStartOffset &&
|
|
ui64Position <= m_uiBufferStartOffset + m_uiBufferBytes)
|
|
{
|
|
m_uiBufferOffset = (FLMUINT)(ui64Position - m_uiBufferStartOffset);
|
|
}
|
|
else
|
|
{
|
|
if( !m_bDataEncrypted)
|
|
{
|
|
if( RC_BAD( rc = m_pBTree->btSetReadPosition( m_ucKey,
|
|
m_uiKeyLength, (FLMUINT)ui64Position)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_uiBufferStartOffset = (FLMUINT)ui64Position;
|
|
m_uiBufferOffset = 0;
|
|
m_uiBufferBytes = 0;
|
|
}
|
|
else
|
|
{
|
|
// When the data is encrypted, we can't just position the btree to a
|
|
// new read position. We must read the data chunk by chunk until we
|
|
// get to the buffer that holds the specified position. Then we can
|
|
// decrypt the buffer and set the correct position.
|
|
|
|
m_bBufferDecrypted = FALSE;
|
|
|
|
if( ui64Position > m_uiBufferStartOffset + m_uiBufferBytes)
|
|
{
|
|
while( ui64Position > m_uiBufferStartOffset + m_uiBufferBytes)
|
|
{
|
|
m_uiBufferStartOffset += m_uiBufferBytes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while( ui64Position < m_uiBufferStartOffset)
|
|
{
|
|
m_uiBufferStartOffset -= f_min( m_uiBufferStartOffset,
|
|
FLM_ENCRYPT_CHUNK_SIZE);
|
|
}
|
|
}
|
|
|
|
flmAssert( ui64Position >= m_uiBufferStartOffset &&
|
|
ui64Position <= m_uiBufferStartOffset + m_uiBufferBytes);
|
|
|
|
// If the new position uis out of range, we will get an error returned.
|
|
|
|
if( RC_BAD( rc = m_pBTree->btSetReadPosition( m_ucKey,
|
|
m_uiKeyLength, m_uiBufferStartOffset)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pBTree->btGetEntry(
|
|
m_ucKey, m_uiKeyLength, m_uiKeyLength,
|
|
m_pucBuffer, m_uiBufferSize, &m_uiBufferBytes)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
if( !m_uiBufferBytes)
|
|
{
|
|
goto Exit;
|
|
}
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
flmAssert( m_uiBufferBytes <= FLM_ENCRYPT_CHUNK_SIZE);
|
|
|
|
if( RC_BAD( rc = m_pDb->decryptData( m_uiEncDefId, m_ucIV,
|
|
m_pucBuffer, m_uiBufferBytes, m_pucBuffer, m_uiBufferSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Check to see if we are at the end of the encrypted data.
|
|
|
|
if( m_uiBufferStartOffset + m_uiBufferBytes >= m_uiDataLength)
|
|
{
|
|
// Trim back to the valid decrypted data.
|
|
|
|
m_uiBufferBytes -= (ENCRYPT_MIN_CHUNK_SIZE -
|
|
extraEncBytes( m_uiDataLength));
|
|
}
|
|
|
|
m_bBufferDecrypted = TRUE;
|
|
m_uiBufferOffset = (FLMUINT)(ui64Position - m_uiBufferStartOffset);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_BTreeIStream::read(
|
|
void * pvBuffer,
|
|
FLMUINT uiBytesToRead,
|
|
FLMUINT * puiBytesRead)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
|
|
FLMUINT uiBufBytesAvail;
|
|
FLMUINT uiTmp;
|
|
FLMUINT uiOffset = 0;
|
|
|
|
flmAssert( m_pBTree);
|
|
|
|
if( m_bDataEncrypted && !m_bBufferDecrypted)
|
|
{
|
|
if( (m_uiBufferBytes - m_uiBufferOffset) > 0)
|
|
{
|
|
// Since we are now looking at encrypted data that was not
|
|
// decrypted, we will need to move the data to the front of the
|
|
// buffer, then read in enough data to fill the buffer (if there
|
|
// is any there) before we can decrypt it.
|
|
|
|
f_memmove( &m_ucBuffer[0], &m_ucBuffer[ m_uiBufferOffset],
|
|
(m_uiBufferBytes - m_uiBufferOffset));
|
|
m_uiBufferBytes -= m_uiBufferOffset;
|
|
m_uiBufferOffset = 0;
|
|
|
|
// Fill the remainder of the buffer
|
|
|
|
if( RC_BAD( rc = m_pBTree->btGetEntry(
|
|
m_ucKey, m_uiKeyLength, m_uiKeyLength,
|
|
&m_ucBuffer[ m_uiBufferBytes], m_uiBufferSize - m_uiBufferBytes,
|
|
&uiTmp)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
m_uiBufferBytes += uiTmp;
|
|
|
|
flmAssert( extraEncBytes( m_uiBufferBytes) == 0);
|
|
flmAssert( m_uiBufferBytes <= FLM_ENCRYPT_CHUNK_SIZE);
|
|
|
|
// Now decrypt what we have.
|
|
|
|
uiTmp = m_uiBufferBytes;
|
|
if( RC_BAD( rc = m_pDb->decryptData( m_uiEncDefId, m_ucIV,
|
|
m_ucBuffer, m_uiBufferBytes, m_ucBuffer, m_uiBufferSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Check for the end of the data.
|
|
|
|
if( m_uiBufferStartOffset + m_uiBufferBytes > m_uiDataLength)
|
|
{
|
|
// Trim back the buffer to valid data only.
|
|
m_uiBufferBytes -= (ENCRYPT_MIN_CHUNK_SIZE -
|
|
extraEncBytes( m_uiDataLength));
|
|
}
|
|
|
|
m_bBufferDecrypted = TRUE;
|
|
}
|
|
}
|
|
|
|
while( uiBytesToRead)
|
|
{
|
|
if( (uiBufBytesAvail = m_uiBufferBytes - m_uiBufferOffset) != 0)
|
|
{
|
|
uiTmp = f_min( uiBufBytesAvail, uiBytesToRead);
|
|
if( pucBuffer)
|
|
{
|
|
f_memcpy( &pucBuffer[ uiOffset],
|
|
&m_pucBuffer[ m_uiBufferOffset], uiTmp);
|
|
}
|
|
m_uiBufferOffset += uiTmp;
|
|
uiOffset += uiTmp;
|
|
if( (uiBytesToRead -= uiTmp) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_uiBufferStartOffset += m_uiBufferBytes;
|
|
m_uiBufferOffset = 0;
|
|
|
|
if( RC_BAD( rc = m_pBTree->btGetEntry(
|
|
m_ucKey, m_uiKeyLength, m_uiKeyLength,
|
|
m_pucBuffer, m_uiBufferSize, &m_uiBufferBytes)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
if( !m_uiBufferBytes)
|
|
{
|
|
goto Exit;
|
|
}
|
|
rc = NE_XFLM_OK;
|
|
continue;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
// Check for encryption.
|
|
|
|
if( m_bDataEncrypted)
|
|
{
|
|
flmAssert( m_uiBufferBytes <= FLM_ENCRYPT_CHUNK_SIZE);
|
|
|
|
if( RC_BAD( rc = m_pDb->decryptData( m_uiEncDefId, m_ucIV,
|
|
m_pucBuffer, m_uiBufferBytes, m_pucBuffer, m_uiBufferSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Check to see if we are at the end of the encrypted data.
|
|
|
|
if( m_uiBufferStartOffset + m_uiBufferBytes > m_uiDataLength)
|
|
{
|
|
// Trim back to the valid decrypted data.
|
|
|
|
m_uiBufferBytes -= (ENCRYPT_MIN_CHUNK_SIZE -
|
|
extraEncBytes( m_uiDataLength));
|
|
}
|
|
|
|
m_bBufferDecrypted = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( puiBytesRead)
|
|
{
|
|
*puiBytesRead = uiOffset;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::decryptData(
|
|
FLMUINT uiEncDefId,
|
|
FLMBYTE * pucIV,
|
|
void * pvInBuf,
|
|
FLMUINT uiInLen,
|
|
void * pvOutBuf,
|
|
FLMUINT uiOutBufSize)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Dict * pDict;
|
|
F_ENCDEF * pEncDef = NULL;
|
|
FLMBYTE * pucInBuf = (FLMBYTE *)pvInBuf;
|
|
FLMBYTE * pucOutBuf = (FLMBYTE *)pvOutBuf;
|
|
FLMUINT uiEncLen;
|
|
FLMUINT uiOutLen;
|
|
|
|
if( m_pDatabase->m_bInLimitedMode)
|
|
{
|
|
rc = RC_SET( m_pDatabase->m_rcLimitedCode);
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( extraEncBytes( uiInLen) == 0);
|
|
flmAssert( uiEncDefId);
|
|
|
|
// Need the dictionary and encryption definition.
|
|
|
|
if( RC_BAD( rc = getDictionary( &pDict)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDict->getEncDef( uiEncDefId, &pEncDef)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( pEncDef);
|
|
flmAssert( pEncDef->pCcs);
|
|
flmAssert( pEncDef->uiEncKeySize);
|
|
|
|
while( uiInLen)
|
|
{
|
|
uiEncLen = f_min( uiInLen, FLM_ENCRYPT_CHUNK_SIZE);
|
|
uiOutLen = uiOutBufSize;
|
|
|
|
if( RC_BAD( rc = pEncDef->pCcs->decryptFromStore(
|
|
pucInBuf, uiEncLen, pucOutBuf, &uiOutLen, pucIV)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( uiOutLen == uiEncLen);
|
|
|
|
pucInBuf += uiEncLen;
|
|
uiInLen -= uiEncLen;
|
|
|
|
pucOutBuf += uiEncLen;
|
|
uiOutBufSize -= uiEncLen;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
F_NodePool::~F_NodePool()
|
|
{
|
|
F_BTreeIStream * pTmpBTreeIStream;
|
|
|
|
while( (pTmpBTreeIStream = m_pFirstBTreeIStream) != NULL)
|
|
{
|
|
m_pFirstBTreeIStream = m_pFirstBTreeIStream->m_pNextInPool;
|
|
pTmpBTreeIStream->m_refCnt = 0;
|
|
pTmpBTreeIStream->m_pNextInPool = NULL;
|
|
delete pTmpBTreeIStream;
|
|
}
|
|
|
|
if( m_hMutex != F_MUTEX_NULL)
|
|
{
|
|
f_mutexDestroy( &m_hMutex);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_NodePool::setup( void)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
|
|
if( RC_BAD( rc = f_mutexCreate( &m_hMutex)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
void F_NodeCacheMgr::insertDOMNode(
|
|
F_DOMNode * pNode)
|
|
{
|
|
|
|
flmAssert( pNode->m_refCnt == 1);
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
pNode->resetDOMNode( TRUE);
|
|
pNode->m_pNextInPool = m_pFirstNode;
|
|
m_pFirstNode = pNode;
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_NodePool::allocBTreeIStream(
|
|
F_BTreeIStream ** ppBTreeIStream)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
|
|
if( m_pFirstBTreeIStream)
|
|
{
|
|
f_mutexLock( m_hMutex);
|
|
if( !m_pFirstBTreeIStream)
|
|
{
|
|
f_mutexUnlock( m_hMutex);
|
|
}
|
|
else
|
|
{
|
|
f_resetStackInfo( m_pFirstBTreeIStream);
|
|
*ppBTreeIStream = m_pFirstBTreeIStream;
|
|
m_pFirstBTreeIStream = m_pFirstBTreeIStream->m_pNextInPool;
|
|
(*ppBTreeIStream)->m_pNextInPool = NULL;
|
|
|
|
f_mutexUnlock( m_hMutex);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( (*ppBTreeIStream = f_new F_BTreeIStream) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_MEM);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
void F_NodePool::insertBTreeIStream(
|
|
F_BTreeIStream * pBTreeIStream)
|
|
{
|
|
flmAssert( pBTreeIStream->m_refCnt == 1);
|
|
|
|
pBTreeIStream->reset();
|
|
f_mutexLock( m_hMutex);
|
|
pBTreeIStream->m_pNextInPool = m_pFirstBTreeIStream;
|
|
m_pFirstBTreeIStream = pBTreeIStream;
|
|
f_mutexUnlock( m_hMutex);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE F_DOMNode::getNamespaceURI(
|
|
FLMBOOL bUnicode,
|
|
IF_Db * ifpDb,
|
|
void * pvNamespaceURI,
|
|
FLMUINT uiBufSize,
|
|
FLMUINT * puiCharsReturned)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiTag;
|
|
FLMUNICODE * puzNamespaceURI;
|
|
char * pszNamespaceURI;
|
|
FLMUINT uiChars = 0;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMUINT uiNameId;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pNameTable = pDb->m_pDict->getNameTable();
|
|
eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
uiTag = ELM_ELEMENT_TAG;
|
|
uiNameId = getNameId();
|
|
}
|
|
else if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
uiTag = ELM_ATTRIBUTE_TAG;
|
|
uiNameId = m_uiAttrNameId;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
uiChars = uiBufSize;
|
|
if( bUnicode)
|
|
{
|
|
puzNamespaceURI = (FLMUNICODE *)pvNamespaceURI;
|
|
pszNamespaceURI = NULL;
|
|
}
|
|
else
|
|
{
|
|
puzNamespaceURI = NULL;
|
|
pszNamespaceURI = (char *)pvNamespaceURI;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndNum(
|
|
pDb, uiTag, uiNameId, NULL, NULL, NULL, NULL,
|
|
puzNamespaceURI, pszNamespaceURI, &uiChars, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( puiCharsReturned)
|
|
{
|
|
*puiCharsReturned = uiChars;
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE F_DOMNode::getLocalName(
|
|
FLMBOOL bUnicode,
|
|
IF_Db * ifpDb,
|
|
void * pvLocalName,
|
|
FLMUINT uiBufSize,
|
|
FLMUINT * puiCharsReturned)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiTag;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMUINT uiChars = 0;
|
|
FLMUINT uiNameId;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pNameTable = pDb->m_pDict->getNameTable();
|
|
eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
uiTag = ELM_ELEMENT_TAG;
|
|
uiNameId = getNameId();
|
|
}
|
|
else if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
uiTag = ELM_ATTRIBUTE_TAG;
|
|
uiNameId = m_uiAttrNameId;
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
uiChars = uiBufSize;
|
|
|
|
if( bUnicode)
|
|
{
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndNum( pDb,
|
|
uiTag, uiNameId, (FLMUNICODE *)pvLocalName, NULL, &uiChars)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndNum( pDb,
|
|
uiTag, uiNameId, NULL, (char *)pvLocalName, &uiChars)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( puiCharsReturned)
|
|
{
|
|
*puiCharsReturned = uiChars;
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Return the prefix name, either as Unicode or as Native.
|
|
*****************************************************************************/
|
|
RCODE F_DOMNode::getPrefix(
|
|
FLMBOOL bUnicode,
|
|
IF_Db * ifpDb,
|
|
void * pvPrefix,
|
|
FLMUINT uiBufSize,
|
|
FLMUINT * puiCharsReturned)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiPrefix;
|
|
FLMUNICODE * puzPrefix = (FLMUNICODE *)pvPrefix;
|
|
char * pszPrefix = (char *)pvPrefix;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
uiPrefix = getPrefixId();
|
|
}
|
|
else if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getPrefixId(
|
|
m_uiAttrNameId, &uiPrefix)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiPrefix)
|
|
{
|
|
if( bUnicode)
|
|
{
|
|
if( RC_BAD( rc = pDb->m_pDict->getPrefix(
|
|
uiPrefix, puzPrefix, uiBufSize, puiCharsReturned)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pDb->m_pDict->getPrefix(
|
|
uiPrefix, pszPrefix, uiBufSize, puiCharsReturned)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( uiBufSize)
|
|
{
|
|
if( puzPrefix)
|
|
{
|
|
*puzPrefix = 0;
|
|
}
|
|
}
|
|
|
|
if( puiCharsReturned)
|
|
{
|
|
*puiCharsReturned = 0;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getQualifiedName(
|
|
IF_Db * ifpDb,
|
|
FLMUNICODE * puzQualifiedName,
|
|
FLMUINT uiBufSize,
|
|
FLMUINT * puiCharsReturned)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiCharsReturned;
|
|
FLMUINT uiTmp;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getPrefix( ifpDb, puzQualifiedName,
|
|
uiBufSize, &uiCharsReturned)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiCharsReturned)
|
|
{
|
|
if( puzQualifiedName)
|
|
{
|
|
uiBufSize -= (sizeof( FLMUNICODE) * uiCharsReturned);
|
|
if( uiBufSize < sizeof( FLMUNICODE) * 2)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
puzQualifiedName[ uiCharsReturned] = FLM_UNICODE_COLON;
|
|
uiCharsReturned++;
|
|
puzQualifiedName += uiCharsReturned;
|
|
uiBufSize -= sizeof( FLMUNICODE);
|
|
}
|
|
else
|
|
{
|
|
uiCharsReturned++;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = getLocalName( ifpDb, puzQualifiedName, uiBufSize, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiCharsReturned += uiTmp;
|
|
|
|
if( puiCharsReturned)
|
|
{
|
|
*puiCharsReturned = uiCharsReturned;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::getQualifiedName(
|
|
IF_Db * ifpDb,
|
|
char * pszQualifiedName,
|
|
FLMUINT uiBufSize,
|
|
FLMUINT * puiCharsReturned)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiCharsReturned;
|
|
FLMUINT uiTmp;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getPrefix( ifpDb,
|
|
pszQualifiedName, uiBufSize, &uiCharsReturned)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiCharsReturned)
|
|
{
|
|
if( pszQualifiedName)
|
|
{
|
|
uiBufSize -= uiCharsReturned;
|
|
if( uiBufSize < 2)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
pszQualifiedName[ uiCharsReturned] = ASCII_COLON;
|
|
uiCharsReturned++;
|
|
pszQualifiedName += uiCharsReturned;
|
|
uiBufSize--;
|
|
}
|
|
else
|
|
{
|
|
uiCharsReturned++;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = getLocalName( ifpDb,
|
|
pszQualifiedName, uiBufSize, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiCharsReturned += uiTmp;
|
|
|
|
if( puiCharsReturned)
|
|
{
|
|
*puiCharsReturned = uiCharsReturned;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Method to set the prefix on a DOM node. Either a unicode or native
|
|
buffer may be used. ** private **
|
|
*****************************************************************************/
|
|
RCODE F_DOMNode::setPrefix(
|
|
FLMBOOL bUnicode,
|
|
IF_Db * ifpDb,
|
|
void * pvPrefix)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiPrefixId;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
char * pszPrefix = (char *)pvPrefix;
|
|
FLMUNICODE * puzPrefix = (FLMUNICODE *)pvPrefix;
|
|
eDomNodeType eNodeType;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If the node is read-only, don't allow it to be changed
|
|
|
|
if( getModeFlags() & FDOM_READ_ONLY)
|
|
{
|
|
rc = RC_SET( NE_XFLM_READ_ONLY);
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
// Make sure this is an element or attribute node
|
|
|
|
if( eNodeType != ELEMENT_NODE && eNodeType != ATTRIBUTE_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
uiPrefixId = 0;
|
|
if( puzPrefix && bUnicode)
|
|
{
|
|
// Find the prefix ID
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getPrefixId( pDb,
|
|
puzPrefix, &uiPrefixId)))
|
|
{
|
|
if( rc == NE_XFLM_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_PREFIX);
|
|
}
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( pszPrefix)
|
|
{
|
|
// Find the prefix ID
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getPrefixId( pDb,
|
|
pszPrefix, &uiPrefixId)))
|
|
{
|
|
if( rc == NE_XFLM_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_PREFIX);
|
|
}
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Set the prefix
|
|
|
|
if( RC_BAD( rc = setPrefixId( ifpDb, uiPrefixId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_DOMNode::setPrefixId(
|
|
IF_Db * ifpDb,
|
|
FLMUINT uiPrefixId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Db * pDb = (F_Db *)ifpDb;
|
|
F_Rfl * pRfl = pDb->m_pDatabase->m_pRfl;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
eDomNodeType eNodeType;
|
|
FLMUINT uiTmp;
|
|
|
|
if( RC_BAD( rc = pDb->checkTransaction(
|
|
XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the node is current
|
|
|
|
if( RC_BAD( rc = syncFromDb( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If the node is read-only, don't allow it to be changed
|
|
|
|
if( getModeFlags() & FDOM_READ_ONLY)
|
|
{
|
|
rc = RC_SET( NE_XFLM_READ_ONLY);
|
|
goto Exit;
|
|
}
|
|
|
|
eNodeType = getNodeType();
|
|
|
|
// If the prefix isn't changing, don't do anything
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->getPrefixId(
|
|
m_uiAttrNameId, &uiTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiPrefixId == uiTmp)
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
if( uiPrefixId == getPrefixId())
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
// Verify that the prefix is valid
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getPrefix(
|
|
uiPrefixId, (char *)NULL, 0, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Set the new prefix
|
|
|
|
if( RC_BAD( rc = makeWriteCopy( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
if( RC_BAD( rc = m_pCachedNode->setPrefixId( pDb,
|
|
m_uiAttrNameId, uiPrefixId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setPrefixId( uiPrefixId);
|
|
}
|
|
|
|
// Update the node
|
|
|
|
if( RC_BAD( rc = pDb->updateNode( m_pCachedNode, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the update
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeSetPrefixId( pDb,
|
|
getCollection(), getIxNodeId(),
|
|
m_uiAttrNameId, uiPrefixId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
if( bMustAbortOnError)
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = pDb->transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Method to compare two dom nodes.
|
|
*****************************************************************************/
|
|
FLMUINT FLMAPI F_DOMNode::compareNode(
|
|
IF_DOMNode * pNode,
|
|
IF_Db * pDb1,
|
|
IF_Db * pDb2,
|
|
char * pszErrBuff,
|
|
FLMUINT uiErrBuffLen)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiEqual = 0;
|
|
F_DOMNode * pLeftNode = (F_DOMNode *)this;
|
|
F_DOMNode * pRightNode = (F_DOMNode *)pNode;
|
|
char szBuffer[ 100];
|
|
FLMUNICODE * puzVal1 = NULL;
|
|
FLMUNICODE * puzVal2 = NULL;
|
|
char * pucBinary1 = NULL;
|
|
char * pucBinary2 = NULL;
|
|
FLMUINT uiBytesReturned1;
|
|
FLMUINT uiBytesReturned2;
|
|
FLMUINT uiDataLen1;
|
|
FLMUINT uiDataLen2;
|
|
FLMUINT uiTmp1;
|
|
FLMUINT uiTmp2;
|
|
FLMUINT64 ui64Tmp1;
|
|
FLMUINT64 ui64Tmp2;
|
|
|
|
#define NODE_NOT_EQUAL 1
|
|
|
|
szBuffer[0] = '\0';
|
|
|
|
if( pLeftNode->getNodeType() != pRightNode->getNodeType())
|
|
{
|
|
f_sprintf( szBuffer, "Node Type mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getDataType( pDb1, &uiTmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getDataType( pDb2, &uiTmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiTmp1 != uiTmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Data Type mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( pLeftNode->getCollection() != pRightNode->getCollection())
|
|
{
|
|
f_sprintf( szBuffer, "Collection mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getPrefixId( pDb1, &uiTmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getPrefixId( pDb2, &uiTmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiTmp1 != uiTmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Prefix mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getNameId( pDb1, &uiTmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getNameId( pDb2, &uiTmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiTmp1 != uiTmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Name Id mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getEncDefId( pDb1, &uiTmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getEncDefId( pDb2, &uiTmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiTmp1 != uiTmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Encryption Id mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pLeftNode->getModeFlags() & FDOM_PERSISTENT_FLAGS) !=
|
|
(pRightNode->getModeFlags() & FDOM_PERSISTENT_FLAGS))
|
|
{
|
|
f_sprintf( szBuffer, "Flags mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getNodeId( pDb1, &ui64Tmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getNodeId( pDb2, &ui64Tmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64Tmp1 != ui64Tmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Node Id mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getDocumentId( pDb1, &ui64Tmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getDocumentId( pDb2, &ui64Tmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64Tmp1 != ui64Tmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Root Node mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getParentId( pDb1, &ui64Tmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getParentId( pDb2, &ui64Tmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64Tmp1 != ui64Tmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Parent Node mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getFirstChildId( pDb1, &ui64Tmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getFirstChildId( pDb2, &ui64Tmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64Tmp1 != ui64Tmp2)
|
|
{
|
|
f_sprintf( szBuffer, "First Child Node mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getLastChildId( pDb1, &ui64Tmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getLastChildId( pDb2, &ui64Tmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64Tmp1 != ui64Tmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Last Child Node mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getPrevSibId( pDb1, &ui64Tmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getPrevSibId( pDb2, &ui64Tmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64Tmp1 != ui64Tmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Previous Sibling Node mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getNextSibId( pDb1, &ui64Tmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getNextSibId( pDb2, &ui64Tmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64Tmp1 != ui64Tmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Next Sibling Node mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getAnnotationId( pDb1, &ui64Tmp1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getAnnotationId( pDb2, &ui64Tmp2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64Tmp1 != ui64Tmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Annotation Node mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getDataLength( pDb1, &uiDataLen1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getDataLength( pDb2, &uiDataLen2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiDataLen1 != uiDataLen2)
|
|
{
|
|
f_sprintf( szBuffer, "Data Length mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiDataLen1)
|
|
{
|
|
switch( pLeftNode->getDataType())
|
|
{
|
|
case XFLM_NODATA_TYPE:
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
case XFLM_TEXT_TYPE:
|
|
{
|
|
|
|
if( RC_BAD( rc = pLeftNode->getUnicode( pDb1, &puzVal1)))
|
|
{
|
|
f_sprintf( szBuffer, "getUnicode failed with rc==0x%04X.",
|
|
(unsigned)rc);
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getUnicode( pDb2, &puzVal2)))
|
|
{
|
|
f_sprintf( szBuffer, "getUnicode failed with rc==0x%04X.",
|
|
(unsigned)rc);
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( f_unicmp( puzVal1, puzVal2) != 0)
|
|
{
|
|
f_sprintf( szBuffer, "Data Value mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XFLM_NUMBER_TYPE:
|
|
{
|
|
if( RC_BAD( rc = pLeftNode->getUINT64( pDb1, &ui64Tmp1)))
|
|
{
|
|
f_sprintf( szBuffer, "getUINT64 failed with rc==0x%04X.",
|
|
(unsigned)rc);
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getUINT64( pDb2, &ui64Tmp2)))
|
|
{
|
|
f_sprintf( szBuffer, "getUINT64 failed with rc==0x%04X.",
|
|
(unsigned)rc);
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( ui64Tmp1 != ui64Tmp2)
|
|
{
|
|
f_sprintf( szBuffer, "Data Value mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XFLM_BINARY_TYPE:
|
|
{
|
|
if( RC_BAD( rc = f_alloc( uiDataLen1 + 1, &pucBinary1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = f_alloc( uiDataLen2 + 1, &pucBinary2)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pLeftNode->getBinary( pDb1, pucBinary1,
|
|
0, uiDataLen1, &uiBytesReturned1)))
|
|
{
|
|
f_sprintf( szBuffer, "getBinary failed with rc==0x%04X.",
|
|
(unsigned)rc);
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRightNode->getBinary(
|
|
pDb2, pucBinary2, 0, uiDataLen2, &uiBytesReturned2)))
|
|
{
|
|
f_sprintf( szBuffer, "getBinary failed with rc==0x%04X.",
|
|
(unsigned)rc);
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiBytesReturned1 != uiBytesReturned2)
|
|
{
|
|
f_sprintf( szBuffer, "Return data length mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
if( f_memcmp( pucBinary1, pucBinary2, uiBytesReturned1) != 0)
|
|
{
|
|
f_strcpy( szBuffer, "Data Value mismatch");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
f_strcpy( szBuffer, "Invalid Data Type");
|
|
uiEqual = NODE_NOT_EQUAL;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
f_memcpy( pszErrBuff, szBuffer, f_min( uiErrBuffLen, f_strlen( szBuffer)));
|
|
pszErrBuff[ f_min( uiErrBuffLen, f_strlen( szBuffer))] = '\0';
|
|
|
|
if( puzVal1)
|
|
{
|
|
f_free( &puzVal1);
|
|
}
|
|
|
|
if( puzVal2)
|
|
{
|
|
f_free( &puzVal2);
|
|
}
|
|
|
|
if( pucBinary1)
|
|
{
|
|
f_free( &pucBinary1);
|
|
}
|
|
|
|
if( pucBinary2)
|
|
{
|
|
f_free( &pucBinary2);
|
|
}
|
|
|
|
return( uiEqual);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_Db::getDictionaryDef(
|
|
FLMUINT uiDictType,
|
|
FLMUINT uiDictNumber,
|
|
IF_DOMNode ** ppDocumentNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_DataVector searchKey;
|
|
F_DataVector foundKey;
|
|
|
|
searchKey.reset();
|
|
foundKey.reset();
|
|
|
|
if( RC_BAD( rc = checkTransaction(
|
|
XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = searchKey.setUINT( 0, uiDictType)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = searchKey.setUINT( 1, uiDictNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = keyRetrieve( XFLM_DICT_NUMBER_INDEX,
|
|
&searchKey, XFLM_EXACT, &foundKey)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNode( XFLM_DICT_COLLECTION,
|
|
foundKey.getDocumentID(), ppDocumentNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getElementNameId(
|
|
const FLMUNICODE * puzNamespaceURI,
|
|
const FLMUNICODE * puzElementName,
|
|
FLMUINT * puiElementNameId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNameTable( &pNameTable)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
|
|
this, ELM_ELEMENT_TAG, puzElementName, NULL,
|
|
TRUE, puzNamespaceURI, puiElementNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNameTable)
|
|
{
|
|
pNameTable->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getElementNameId(
|
|
const char * pszNamespaceURI,
|
|
const char * pszElementName,
|
|
FLMUINT * puiElementNameId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUNICODE * puzNamespaceURI = NULL;
|
|
FLMUNICODE * puzTmp;
|
|
const char * pszTmp;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNameTable( &pNameTable)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pszNamespaceURI && *pszNamespaceURI)
|
|
{
|
|
if( RC_BAD( rc = f_alloc( (f_strlen( pszNamespaceURI) + 1) *
|
|
sizeof( FLMUNICODE), &puzNamespaceURI)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pszTmp = pszNamespaceURI;
|
|
puzTmp = puzNamespaceURI;
|
|
|
|
while (*pszTmp)
|
|
{
|
|
*puzTmp = (FLMUNICODE)(*pszTmp);
|
|
pszTmp++;
|
|
puzTmp++;
|
|
}
|
|
|
|
*puzTmp = 0;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
|
|
this, ELM_ELEMENT_TAG, NULL, pszElementName,
|
|
TRUE, puzNamespaceURI, puiElementNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNameTable)
|
|
{
|
|
pNameTable->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
if( puzNamespaceURI)
|
|
{
|
|
f_free( &puzNamespaceURI);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getAttributeNameId(
|
|
const FLMUNICODE * puzNamespaceURI,
|
|
const FLMUNICODE * puzAttributeName,
|
|
FLMUINT * puiAttributeNameId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNameTable( &pNameTable)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
|
|
this, ELM_ATTRIBUTE_TAG, puzAttributeName, NULL,
|
|
TRUE, puzNamespaceURI, puiAttributeNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNameTable)
|
|
{
|
|
pNameTable->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getAttributeNameId(
|
|
const char * pszNamespaceURI,
|
|
const char * pszAttributeName,
|
|
FLMUINT * puiAttributeNameId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUNICODE * puzNamespaceURI = NULL;
|
|
FLMUNICODE * puzTmp;
|
|
const char * pszTmp;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNameTable( &pNameTable)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pszNamespaceURI && *pszNamespaceURI)
|
|
{
|
|
if( RC_BAD( rc = f_alloc( (f_strlen( pszNamespaceURI) + 1) *
|
|
sizeof( FLMUNICODE), &puzNamespaceURI)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pszTmp = pszNamespaceURI;
|
|
puzTmp = puzNamespaceURI;
|
|
|
|
while (*pszTmp)
|
|
{
|
|
*puzTmp = (FLMUNICODE)(*pszTmp);
|
|
pszTmp++;
|
|
puzTmp++;
|
|
}
|
|
|
|
*puzTmp = 0;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
|
|
this, ELM_ATTRIBUTE_TAG, NULL, pszAttributeName,
|
|
TRUE, puzNamespaceURI, puiAttributeNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNameTable)
|
|
{
|
|
pNameTable->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
if( puzNamespaceURI)
|
|
{
|
|
f_free( &puzNamespaceURI);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Get a collection number from collection name.
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getCollectionNumber(
|
|
const char * pszCollectionName,
|
|
FLMUINT * puiCollectionNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNameTable( &pNameTable)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
|
|
this, ELM_COLLECTION_TAG, NULL, pszCollectionName,
|
|
FALSE, NULL, puiCollectionNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNameTable)
|
|
{
|
|
pNameTable->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Get a collection number from collection name.
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getCollectionNumber(
|
|
const FLMUNICODE * puzCollectionName,
|
|
FLMUINT * puiCollectionNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNameTable( &pNameTable)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
|
|
this, ELM_COLLECTION_TAG, puzCollectionName, NULL,
|
|
FALSE, NULL, puiCollectionNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNameTable)
|
|
{
|
|
pNameTable->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Get an index number from index name.
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getIndexNumber(
|
|
const char * pszIndexName,
|
|
FLMUINT * puiIndexNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNameTable( &pNameTable)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
|
|
this, ELM_INDEX_TAG, NULL, pszIndexName,
|
|
FALSE, NULL, puiIndexNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNameTable)
|
|
{
|
|
pNameTable->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Get an index number from index name.
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getIndexNumber(
|
|
const FLMUNICODE * puzIndexName,
|
|
FLMUINT * puiIndexNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_NameTable * pNameTable = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNameTable( &pNameTable)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNameTable->getFromTagTypeAndName(
|
|
this, ELM_INDEX_TAG, puzIndexName, NULL,
|
|
FALSE, NULL, puiIndexNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNameTable)
|
|
{
|
|
pNameTable->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::createDocument(
|
|
FLMUINT uiCollection,
|
|
IF_DOMNode ** ppDocument,
|
|
FLMUINT64 * pui64NodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
|
|
if( uiCollection == XFLM_MAINT_COLLECTION)
|
|
{
|
|
// Users are not allowed to create documents in the
|
|
// maintenance collection
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = createRootNode( uiCollection, 0,
|
|
DOCUMENT_NODE, (F_DOMNode **)ppDocument, pui64NodeId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::createRootElement(
|
|
FLMUINT uiCollection,
|
|
FLMUINT uiNameId,
|
|
IF_DOMNode ** ppElement,
|
|
FLMUINT64 * pui64NodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
|
|
if( uiCollection == XFLM_MAINT_COLLECTION)
|
|
{
|
|
// Users are not allowed to create documents in the
|
|
// maintenance collection
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = createRootNode( uiCollection, uiNameId,
|
|
ELEMENT_NODE, (F_DOMNode **)ppElement, pui64NodeId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::checkAndUpdateState(
|
|
eDomNodeType eNodeType,
|
|
FLMUINT uiNameId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bUserDefined = FALSE;
|
|
FLMUINT uiDictType = 0;
|
|
F_AttrElmInfo defInfo;
|
|
|
|
// The F_AttrElmInfo constructor should have set the state
|
|
// to active.
|
|
|
|
flmAssert( defInfo.m_uiState == ATTR_ELM_STATE_ACTIVE);
|
|
|
|
if( eNodeType == ATTRIBUTE_NODE)
|
|
{
|
|
uiDictType = ELM_ATTRIBUTE_TAG;
|
|
if( RC_BAD( rc = m_pDict->getAttribute( this, uiNameId, &defInfo)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bUserDefined = attributeIsUserDefined( uiNameId);
|
|
}
|
|
else if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
uiDictType = ELM_ELEMENT_TAG;
|
|
if( RC_BAD( rc = m_pDict->getElement( this, uiNameId, &defInfo)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bUserDefined = elementIsUserDefined( uiNameId);
|
|
}
|
|
else if( eNodeType == DATA_NODE)
|
|
{
|
|
if( uiNameId)
|
|
{
|
|
uiDictType = ELM_ELEMENT_TAG;
|
|
if( RC_BAD( rc = m_pDict->getElement( this, uiNameId, &defInfo)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bUserDefined = elementIsUserDefined( uiNameId);
|
|
}
|
|
}
|
|
else if( eNodeType != COMMENT_NODE &&
|
|
eNodeType != DOCUMENT_NODE &&
|
|
eNodeType != ANNOTATION_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
if( bUserDefined && defInfo.m_uiState != ATTR_ELM_STATE_ACTIVE)
|
|
{
|
|
if( defInfo.m_uiState == ATTR_ELM_STATE_PURGE )
|
|
{
|
|
// Marked as 'purged'. So, user is not allowed to add
|
|
// new instances of this field.
|
|
|
|
rc = (RCODE)(eNodeType == ELEMENT_NODE
|
|
? RC_SET( NE_XFLM_ELEMENT_PURGED)
|
|
: RC_SET( NE_XFLM_ATTRIBUTE_PURGED));
|
|
goto Exit;
|
|
}
|
|
else if( defInfo.m_uiState == ATTR_ELM_STATE_CHECKING)
|
|
{
|
|
// Because an occurance is being added, update the
|
|
// state to be 'active'
|
|
|
|
if( RC_BAD( rc = changeItemState( uiDictType, uiNameId,
|
|
XFLM_ACTIVE_OPTION_STR)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::_updateNode(
|
|
F_CachedNode * pCachedNode,
|
|
FLMUINT uiFlags)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiCollection = pCachedNode->getCollection();
|
|
F_COLLECTION * pCollection;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMBOOL bAdd = (uiFlags & FLM_UPD_ADD) ? TRUE : FALSE;
|
|
F_AttrElmInfo defInfo;
|
|
|
|
// Logging should be done at a higher level
|
|
|
|
flmAssert( !m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
flmAssert( uiCollection);
|
|
|
|
// Mark the node as being dirty
|
|
|
|
pCachedNode->setNodeDirty( this, bAdd);
|
|
|
|
if( bAdd)
|
|
{
|
|
// Get a pointer to the collection
|
|
|
|
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If the nodeId is greater than or equal to the next nodeId, we
|
|
// will set the next nodeId to 1 greater than the new nodeId to avoid
|
|
// running into the same nodeId later.
|
|
//
|
|
// Node ID should already be set at this point.
|
|
|
|
flmAssert( pCachedNode->getNodeId());
|
|
|
|
if( pCachedNode->getNodeId() >= pCollection->ui64NextNodeId)
|
|
{
|
|
pCollection->ui64NextNodeId = pCachedNode->getNodeId() + 1;
|
|
pCollection->bNeedToUpdateNodes = TRUE;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
}
|
|
else if( !pCachedNode->getNodeId())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// Add the document to the list of documents that need to have
|
|
// documentDone called at commit time.
|
|
|
|
if( !(uiFlags & FLM_UPD_INTERNAL_CHANGE) &&
|
|
uiCollection == XFLM_DICT_COLLECTION)
|
|
{
|
|
if( RC_BAD( rc = m_pDatabase->m_DocumentList.addNode(
|
|
pCachedNode->getCollection(), pCachedNode->getDocumentId(), 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::getCachedBTree(
|
|
FLMUINT uiCollection,
|
|
F_Btree ** ppBTree)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_COLLECTION * pCollection;
|
|
|
|
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( m_pCachedBTree)
|
|
{
|
|
flmAssert( m_pCachedBTree->getRefCount() == 1);
|
|
m_pCachedBTree->btClose();
|
|
}
|
|
else
|
|
{
|
|
// Reserve a B-Tree from the pool
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree(
|
|
&m_pCachedBTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Set up the btree object
|
|
|
|
if( RC_BAD( rc = m_pCachedBTree->btOpen( this,
|
|
&pCollection->lfInfo, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_pCachedBTree->AddRef();
|
|
*ppBTree = m_pCachedBTree;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::flushNode(
|
|
F_Btree * pBTree,
|
|
F_CachedNode * pCachedNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_COLLECTION * pCollection;
|
|
FLMUINT64 ui64NodeId = pCachedNode->getNodeId();
|
|
FLMBYTE ucKeyBuf[ FLM_MAX_NUM_BUF_SIZE];
|
|
FLMUINT uiKeyLen;
|
|
FLMUINT uiHeaderStorageSize;
|
|
F_DynaBuf dynaBuf( m_pDatabase->m_pucUpdBuffer, m_pDatabase->m_uiUpdBufferSize);
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
IF_PosIStream * pIStream = NULL;
|
|
FLMBYTE * pucSrc = NULL;
|
|
FLMBYTE * pucTmp;
|
|
FLMBOOL bOutputNodeData;
|
|
FLMBOOL bTruncateOnReplace;
|
|
FLMUINT32 ui32BlkAddr;
|
|
FLMUINT uiOffsetIndex;
|
|
FLMBYTE * pucIV = NULL;
|
|
FLMUINT uiIVLen = 0;
|
|
FLMUINT uiEncDefId = pCachedNode->getEncDefId();
|
|
eDomNodeType eNodeType = pCachedNode->getNodeType();
|
|
FLMUINT uiNodeDataLength;
|
|
|
|
// Node should be dirty
|
|
|
|
flmAssert( pCachedNode->nodeIsDirty());
|
|
|
|
// Transaction IDs should match
|
|
|
|
if( pCachedNode->getLowTransId() != getTransID())
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
uiNodeDataLength = pCachedNode->m_nodeInfo.uiDataLength;
|
|
|
|
// Output the header
|
|
|
|
if( (pCachedNode->getModeFlags() & FDOM_FIXED_SIZE_HEADER) == 0)
|
|
{
|
|
if( RC_BAD( rc = dynaBuf.allocSpace( MAX_DOM_HEADER_SIZE,
|
|
(void **)&pucTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pCachedNode->headerToBuf( FALSE,
|
|
pucTmp, &uiHeaderStorageSize, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
dynaBuf.truncateData( uiHeaderStorageSize);
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = dynaBuf.allocSpace( FIXED_DOM_HEADER_SIZE,
|
|
(void **)&pucTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pCachedNode->headerToBuf( TRUE, pucTmp,
|
|
&uiHeaderStorageSize, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Get a pointer to the collection
|
|
|
|
if( RC_BAD( rc = m_pDict->getCollection( pCachedNode->getCollection(),
|
|
&pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiKeyLen = sizeof( ucKeyBuf);
|
|
if( RC_BAD( rc = flmNumber64ToStorage( ui64NodeId,
|
|
&uiKeyLen, ucKeyBuf, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
FLMUINT uiLoop;
|
|
NODE_ITEM * pNodeItem;
|
|
FLMUINT uiNodeCount = pCachedNode->getChildElmCount();
|
|
FLMUINT uiTmpOffset;
|
|
FLMUINT uiPrevNameId = 0;
|
|
FLMUINT64 ui64ElmNodeId = pCachedNode->getNodeId();
|
|
|
|
// Go through the child element list and output them to the buffer
|
|
// Note that the child element node count has already been output
|
|
// as part of the node header.
|
|
|
|
pNodeItem = pCachedNode->m_pNodeList;
|
|
for( uiLoop = 0; uiLoop < uiNodeCount; pNodeItem++, uiLoop++)
|
|
{
|
|
uiTmpOffset = dynaBuf.getDataLength();
|
|
|
|
if( RC_BAD( rc = dynaBuf.allocSpace( FLM_MAX_SEN_LEN * 2,
|
|
(void **)&pucTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( pNodeItem->uiNameId > uiPrevNameId);
|
|
flmAssert( pNodeItem->ui64NodeId > ui64ElmNodeId);
|
|
|
|
uiTmpOffset += f_encodeSEN( pNodeItem->uiNameId - uiPrevNameId,
|
|
&pucTmp);
|
|
|
|
uiTmpOffset += f_encodeSEN( pNodeItem->ui64NodeId - ui64ElmNodeId,
|
|
&pucTmp);
|
|
|
|
uiPrevNameId = pNodeItem->uiNameId;
|
|
dynaBuf.truncateData( uiTmpOffset);
|
|
}
|
|
|
|
// Export any attributes on the element
|
|
|
|
if( pCachedNode->m_uiAttrCount)
|
|
{
|
|
if( RC_BAD( rc = pCachedNode->exportAttributeList( this,
|
|
&dynaBuf, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set up to output data
|
|
|
|
if( uiNodeDataLength)
|
|
{
|
|
if( pCachedNode->getModeFlags() & FDOM_VALUE_ON_DISK)
|
|
{
|
|
if( pCachedNode->getModeFlags() & FDOM_FIXED_SIZE_HEADER)
|
|
{
|
|
bOutputNodeData = FALSE;
|
|
bTruncateOnReplace = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// If the value is on disk and we don't have a fixed-size header,
|
|
// we'll have to read and output the entire node value.
|
|
|
|
flmAssert( eNodeType != ELEMENT_NODE);
|
|
|
|
if( RC_BAD( rc = pCachedNode->getIStream( this, NULL, &pIStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bOutputNodeData = TRUE;
|
|
bTruncateOnReplace = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pucSrc = pCachedNode->getDataPtr();
|
|
bOutputNodeData = TRUE;
|
|
bTruncateOnReplace = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bOutputNodeData = FALSE;
|
|
bTruncateOnReplace = TRUE;
|
|
}
|
|
|
|
if( bOutputNodeData)
|
|
{
|
|
FLMUINT uiDataOutputSize = uiNodeDataLength;
|
|
|
|
if( uiEncDefId)
|
|
{
|
|
F_ENCDEF * pEncDef;
|
|
|
|
if( RC_BAD( rc = m_pDict->getEncDef( uiEncDefId, &pEncDef)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiIVLen = pEncDef->pCcs->getIVLen();
|
|
flmAssert( uiIVLen == 8 || uiIVLen == 16);
|
|
|
|
if( RC_BAD( rc = dynaBuf.allocSpace( uiIVLen, (void **)&pucIV)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pEncDef->pCcs->generateIV( uiIVLen, pucIV)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiDataOutputSize = getEncLen( uiNodeDataLength);
|
|
}
|
|
|
|
if( RC_BAD( rc = dynaBuf.allocSpace( uiDataOutputSize,
|
|
(void **)&pucTmp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pIStream)
|
|
{
|
|
if( RC_BAD( rc = pIStream->read( pucTmp, uiNodeDataLength, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
f_memcpy( pucTmp, pucSrc, uiNodeDataLength);
|
|
}
|
|
|
|
if( uiEncDefId)
|
|
{
|
|
if( RC_BAD( rc = encryptData( uiEncDefId, pucIV,
|
|
pucTmp, uiDataOutputSize, uiNodeDataLength, &uiDataOutputSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
ui32BlkAddr = pCachedNode->getBlkAddr();
|
|
uiOffsetIndex = pCachedNode->getOffsetIndex();
|
|
|
|
if( pCachedNode->nodeIsNew())
|
|
{
|
|
// If this is a new node, the value will not be on disk.
|
|
// This routine is only called for values that we are
|
|
// keeping in memory. If we stream a value out through
|
|
// multiple buffers, it is written right away and the
|
|
// node's dirty and new flags will be unset as soon as
|
|
// the writing is done.
|
|
|
|
if( pCachedNode->getModeFlags() & FDOM_VALUE_ON_DISK)
|
|
{
|
|
// This shouldn't happen
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_FAILURE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBTree->btInsertEntry(
|
|
ucKeyBuf, uiKeyLen,
|
|
dynaBuf.getBufferPtr(), dynaBuf.getDataLength(),
|
|
TRUE, TRUE, &ui32BlkAddr, &uiOffsetIndex)))
|
|
{
|
|
if( rc == NE_XFLM_NOT_UNIQUE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_EXISTS);
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Replace the node on disk.
|
|
|
|
if( RC_BAD( rc = pBTree->btReplaceEntry(
|
|
ucKeyBuf, uiKeyLen,
|
|
dynaBuf.getBufferPtr(), dynaBuf.getDataLength(),
|
|
TRUE, TRUE, bTruncateOnReplace, &ui32BlkAddr,
|
|
&uiOffsetIndex)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pCachedNode->setBlkAddr( ui32BlkAddr);
|
|
pCachedNode->setOffsetIndex( uiOffsetIndex);
|
|
|
|
// Clear the dirty flag and the new flag.
|
|
|
|
pCachedNode->unsetNodeDirtyAndNew( this);
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::encryptData(
|
|
FLMUINT uiEncDefId,
|
|
FLMBYTE * pucIV,
|
|
FLMBYTE * pucBuffer,
|
|
FLMUINT uiBufferSize,
|
|
FLMUINT uiDataLen,
|
|
FLMUINT * puiOutputLength)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Dict * pDict;
|
|
F_ENCDEF * pEncDef;
|
|
FLMUINT uiEncLen;
|
|
FLMUINT uiTmpLen;
|
|
FLMUINT uiEncBuffLen;
|
|
FLMUINT uiDataToEncrypt = uiDataLen;
|
|
FLMUINT uiChunkLen;
|
|
FLMBYTE * pucEncTmp;
|
|
FLMBYTE ucEncryptBuffer[ FLM_ENCRYPT_CHUNK_SIZE];
|
|
|
|
if( m_pDatabase->m_bInLimitedMode)
|
|
{
|
|
*puiOutputLength = uiDataLen;
|
|
rc = RC_SET( m_pDatabase->m_rcLimitedCode);
|
|
goto Exit;
|
|
}
|
|
|
|
// Need to retrieve the encryption key.
|
|
|
|
if( RC_BAD( rc = getDictionary( &pDict)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDict->getEncDef( uiEncDefId, &pEncDef)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( pEncDef);
|
|
flmAssert( pEncDef->pCcs);
|
|
|
|
// Check first to make sure we wil be able to encrypt the entire buffer
|
|
// since we must return the encrypted data in the source buffer.
|
|
|
|
uiEncLen = getEncLen( uiDataLen);
|
|
|
|
if( uiEncLen > uiBufferSize)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_CONV_DEST_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
// Encrypt the buffer in chunks
|
|
|
|
uiEncBuffLen = 0;
|
|
pucEncTmp = &ucEncryptBuffer[0];
|
|
|
|
while( uiDataToEncrypt)
|
|
{
|
|
FLMUINT uiDataEncrypted;
|
|
|
|
uiDataEncrypted = uiChunkLen = ((uiDataToEncrypt > FLM_ENCRYPT_CHUNK_SIZE)
|
|
? FLM_ENCRYPT_CHUNK_SIZE
|
|
: uiDataToEncrypt);
|
|
|
|
if( extraEncBytes( uiChunkLen) != 0)
|
|
{
|
|
// If we are padding, we *MUST* be on the last piece to encrypt!
|
|
|
|
flmAssert( uiChunkLen == uiDataToEncrypt);
|
|
uiChunkLen += (ENCRYPT_MIN_CHUNK_SIZE - extraEncBytes( uiChunkLen));
|
|
}
|
|
|
|
flmAssert( uiChunkLen <= FLM_ENCRYPT_CHUNK_SIZE);
|
|
|
|
uiTmpLen = uiChunkLen;
|
|
|
|
if( RC_BAD( rc = pEncDef->pCcs->encryptToStore(
|
|
pucBuffer, uiChunkLen, pucEncTmp, &uiTmpLen, pucIV)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( uiTmpLen == uiChunkLen);
|
|
f_memcpy( pucBuffer, pucEncTmp, uiChunkLen);
|
|
|
|
pucBuffer += uiChunkLen;
|
|
uiDataToEncrypt -= uiDataEncrypted;
|
|
uiEncBuffLen += uiChunkLen;
|
|
|
|
flmAssert( uiEncBuffLen <= uiEncLen);
|
|
}
|
|
|
|
flmAssert( uiEncBuffLen == uiEncLen);
|
|
*puiOutputLength = uiEncLen;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::createRootNode(
|
|
FLMUINT uiCollection,
|
|
FLMUINT uiElementNameId,
|
|
eDomNodeType eNodeType,
|
|
F_DOMNode ** ppNewNode,
|
|
FLMUINT64 * pui64NodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Rfl * pRfl = m_pDatabase->m_pRfl;
|
|
F_DOMNode * pPrevSib = NULL;
|
|
F_DOMNode * pNewNode = NULL;
|
|
F_CachedNode * pCachedNode;
|
|
F_COLLECTION * pCollection;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( eNodeType != ELEMENT_NODE && eNodeType != DOCUMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
// If a specific node Id is requested, check to make sure it is not
|
|
// already in use.
|
|
|
|
if( pui64NodeId)
|
|
{
|
|
if( *pui64NodeId && (m_uiFlags & FDB_REBUILDING_DATABASE))
|
|
{
|
|
if( RC_OK( rc = getNode( uiCollection, *pui64NodeId, &pNewNode)))
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
else if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Set the value to zero so we don't use it. We will
|
|
// return the new nodeId.
|
|
|
|
*pui64NodeId = 0;
|
|
}
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
// Check the state if this is a root element
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
if( RC_BAD( rc = checkAndUpdateState( ELEMENT_NODE, uiElementNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->createNode( this,
|
|
uiCollection,
|
|
(FLMUINT64)(pui64NodeId
|
|
? *pui64NodeId
|
|
: (FLMUINT64)0),
|
|
&pNewNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Clone the dictionary since the first/last document ID
|
|
// values of the collection will be changed
|
|
|
|
if( !(m_uiFlags & FDB_UPDATED_DICTIONARY))
|
|
{
|
|
if( RC_BAD( rc = dictClone()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Get a pointer to the collection
|
|
|
|
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pCachedNode = pNewNode->m_pCachedNode;
|
|
|
|
if( !pCollection->ui64FirstDocId)
|
|
{
|
|
pCollection->ui64FirstDocId = pCollection->ui64NextNodeId;
|
|
pCollection->ui64LastDocId = pCollection->ui64NextNodeId;
|
|
}
|
|
else
|
|
{
|
|
pCachedNode->setPrevSibId( pCollection->ui64LastDocId);
|
|
pCollection->ui64LastDocId = pCollection->ui64NextNodeId;
|
|
}
|
|
pCollection->bNeedToUpdateNodes = TRUE;
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
F_AttrElmInfo elmInfo;
|
|
|
|
if( RC_BAD( rc = m_pDict->getElement( this, uiElementNameId, &elmInfo)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pCachedNode->setNameId( uiElementNameId);
|
|
pCachedNode->setDataType( elmInfo.m_uiDataType);
|
|
|
|
// Is this a node whose child elements must all be unique?
|
|
|
|
if( elmInfo.m_uiFlags & ATTR_ELM_UNIQUE_SUBELMS)
|
|
{
|
|
flmAssert( elmInfo.m_uiDataType == XFLM_NODATA_TYPE);
|
|
pCachedNode->setFlags( FDOM_HAVE_CELM_LIST);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCachedNode->setDataType( XFLM_NODATA_TYPE);
|
|
}
|
|
|
|
pCachedNode->setNodeType( eNodeType);
|
|
pCachedNode->setDocumentId( pCachedNode->getNodeId());
|
|
|
|
// Link the document into the document list
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( pui64NodeId && *pui64NodeId)
|
|
{
|
|
pCollection->ui64LastDocId = *pui64NodeId;
|
|
pCollection->bNeedToUpdateNodes = TRUE;
|
|
}
|
|
|
|
// Output the node
|
|
|
|
if( RC_BAD( rc = updateNode( pCachedNode, FLM_UPD_ADD)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Retrieve the previous sibling and set its next sibling
|
|
// value
|
|
|
|
if( pCachedNode->getPrevSibId())
|
|
{
|
|
if( RC_BAD( rc = getNode( uiCollection,
|
|
pCachedNode->getPrevSibId(), &pPrevSib)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pPrevSib->makeWriteCopy( this)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pPrevSib->setNextSibId( pCachedNode->getNodeId());
|
|
|
|
if( RC_BAD( rc = updateNode( pPrevSib->m_pCachedNode,
|
|
FLM_UPD_INTERNAL_CHANGE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Check indexing if it is an element
|
|
|
|
if( eNodeType == ELEMENT_NODE)
|
|
{
|
|
if( RC_BAD( rc = updateIndexKeys(
|
|
uiCollection, pNewNode, IX_ADD_NODE_VALUE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logNodeCreate( this, pCachedNode->getCollection(),
|
|
pCachedNode->getNodeId(), eNodeType, uiElementNameId,
|
|
XFLM_ROOT, pNewNode->getNodeId())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pui64NodeId)
|
|
{
|
|
*pui64NodeId = pCachedNode->getNodeId();
|
|
}
|
|
|
|
if( ppNewNode)
|
|
{
|
|
if( *ppNewNode)
|
|
{
|
|
(*ppNewNode)->Release();
|
|
}
|
|
|
|
*ppNewNode = pNewNode;
|
|
pNewNode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNewNode)
|
|
{
|
|
pNewNode->Release();
|
|
}
|
|
|
|
if( pPrevSib)
|
|
{
|
|
pPrevSib->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::findNode(
|
|
FLMUINT uiCollection,
|
|
FLMUINT64 * pui64NodeId,
|
|
FLMUINT uiFlags)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Btree * pBTree = NULL;
|
|
F_BTreeIStream btreeIStream;
|
|
|
|
// Determine the node's B-Tree address
|
|
|
|
if( RC_BAD( rc = getCachedBTree( uiCollection, &pBTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// At this point, we know that uiFlags is NOT XFLM_EXACT, but is
|
|
// XFLM_INCL, XFLM_EXCL, XFLM_FIRST, or XFLM_LAST. So we will
|
|
// need to reassign ui64NodeId once we have located the node.
|
|
|
|
if( RC_BAD( rc = btreeIStream.open( this, pBTree,
|
|
uiFlags, uiCollection, *pui64NodeId, 0, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
*pui64NodeId = btreeIStream.m_ui64NodeId;
|
|
|
|
// Close the input stream
|
|
|
|
btreeIStream.close();
|
|
|
|
Exit:
|
|
|
|
if( pBTree)
|
|
{
|
|
pBTree->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::getNode(
|
|
FLMUINT uiCollection,
|
|
FLMUINT64 ui64NodeId,
|
|
FLMUINT uiFlags,
|
|
F_DOMNode ** ppNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pNode = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Quick check to see if the user is re-retrieving the same
|
|
// node that is currently pointed to by pNode
|
|
|
|
if( uiFlags == XFLM_EXACT)
|
|
{
|
|
F_DOMNode * pTmpNode;
|
|
|
|
if( ((pTmpNode = *ppNode) != NULL) &&
|
|
pTmpNode->m_pCachedNode && pTmpNode->m_uiAttrNameId == 0)
|
|
{
|
|
if( pTmpNode->getNodeId() == ui64NodeId &&
|
|
pTmpNode->getCollection() == uiCollection &&
|
|
pTmpNode->getDatabase() == m_pDatabase)
|
|
{
|
|
if( RC_BAD( rc = pTmpNode->syncFromDb( this)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_DELETED)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
}
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( getTransType() == XFLM_UPDATE_TRANS)
|
|
{
|
|
// Need to flush dirty nodes through to the B-Tree so that
|
|
// look-ups will work correctly
|
|
|
|
if( RC_BAD( rc = flushDirtyNodes()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = findNode( uiCollection, &ui64NodeId, uiFlags)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Retrieve the node into cache.
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->retrieveNode( this,
|
|
uiCollection, ui64NodeId, &pNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( *ppNode)
|
|
{
|
|
(*ppNode)->Release();
|
|
}
|
|
|
|
*ppNode = pNode;
|
|
pNode = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getAttribute(
|
|
FLMUINT uiCollection,
|
|
FLMUINT64 ui64ElementId,
|
|
FLMUINT uiAttrName,
|
|
IF_DOMNode ** ifppAttr)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pElementNode = NULL;
|
|
F_DOMNode * pAttrNode = NULL;
|
|
F_AttrItem * pAttrItem;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNode( uiCollection, ui64ElementId,
|
|
XFLM_EXACT, &pElementNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pElementNode->getNodeType() != ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pAttrItem = pElementNode->m_pCachedNode->getAttribute( uiAttrName,
|
|
NULL)) == NULL)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttrNode)))
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttrNode->m_pCachedNode = pElementNode->m_pCachedNode;
|
|
pAttrNode->m_pCachedNode->incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
pAttrNode->m_uiAttrNameId = pAttrItem->m_uiNameId;
|
|
|
|
if( ifppAttr)
|
|
{
|
|
if( *ifppAttr)
|
|
{
|
|
(*ifppAttr)->Release();
|
|
}
|
|
|
|
*ifppAttr = (IF_DOMNode *)pAttrNode;
|
|
pAttrNode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttrNode)
|
|
{
|
|
pAttrNode->Release();
|
|
}
|
|
|
|
if( pElementNode)
|
|
{
|
|
pElementNode->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getFirstDocument(
|
|
FLMUINT uiCollection,
|
|
IF_DOMNode ** ppDocumentNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_COLLECTION * pCollection;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pCollection->ui64FirstDocId)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNode( uiCollection, pCollection->ui64FirstDocId,
|
|
ppDocumentNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getLastDocument(
|
|
FLMUINT uiCollection,
|
|
IF_DOMNode ** ppDocumentNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_COLLECTION * pCollection;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pCollection->ui64LastDocId)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNode( uiCollection, pCollection->ui64LastDocId,
|
|
ppDocumentNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE FLMAPI F_Db::getDocument(
|
|
FLMUINT uiCollection,
|
|
FLMUINT uiFlags,
|
|
FLMUINT64 ui64DocumentId,
|
|
IF_DOMNode ** ppDocumentNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_COLLECTION * pCollection;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
F_Btree * pBTree = NULL;
|
|
F_DOMNode * pNode = NULL;
|
|
FLMBYTE ucKey [FLM_MAX_NUM_BUF_SIZE];
|
|
FLMUINT uiKeyLen;
|
|
FLMBOOL bNeg;
|
|
FLMUINT uiBytesProcessed;
|
|
FLMUINT64 ui64NodeId;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
switch (uiFlags)
|
|
{
|
|
case XFLM_FIRST:
|
|
{
|
|
if( RC_BAD( rc = getNode( uiCollection, pCollection->ui64FirstDocId,
|
|
ppDocumentNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XFLM_LAST:
|
|
{
|
|
if( RC_BAD( rc = getNode( uiCollection, pCollection->ui64LastDocId,
|
|
ppDocumentNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XFLM_EXACT:
|
|
{
|
|
if( RC_BAD( rc = getNode( uiCollection, ui64DocumentId, &pNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pNode->isRootNode())
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( *ppDocumentNode)
|
|
{
|
|
(*ppDocumentNode)->Release();
|
|
}
|
|
|
|
// No need to do an AddRef on ppDocumentNode - just use the reference
|
|
// from pNode and set pNode to NULL so it won't be released
|
|
|
|
*ppDocumentNode = pNode;
|
|
pNode = NULL;
|
|
break;
|
|
}
|
|
|
|
case XFLM_INCL:
|
|
case XFLM_EXCL:
|
|
{
|
|
if( getTransType() == XFLM_UPDATE_TRANS)
|
|
{
|
|
// Need to flush dirty nodes through to the B-Tree so that
|
|
// look-ups will work correctly
|
|
|
|
if( RC_BAD( rc = flushDirtyNodes()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Get a btree
|
|
|
|
if( RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pBTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBTree->btOpen( this, &pCollection->lfInfo,
|
|
FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiKeyLen = sizeof( ucKey);
|
|
if( RC_BAD( rc = flmNumber64ToStorage( ui64DocumentId, &uiKeyLen,
|
|
ucKey, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBTree->btLocateEntry(
|
|
ucKey, sizeof( ucKey), &uiKeyLen, XFLM_INCL)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure we hit a root node. If not, continue reading until we do
|
|
// or until we hit the end. Root nodes are always linked together in
|
|
// ascending order, so if there is another document, we will find it
|
|
// simply by searching forward from where we are. Then we can follow
|
|
// document links.
|
|
|
|
for (;;)
|
|
{
|
|
if( RC_BAD( rc = flmCollation2Number( uiKeyLen, ucKey,
|
|
&ui64NodeId, &bNeg, &uiBytesProcessed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = getNode( uiCollection, ui64NodeId, &pNode)))
|
|
{
|
|
if( rc == NE_XFLM_DOM_NODE_NOT_FOUND)
|
|
{
|
|
|
|
// Better be able to find the node at this point!
|
|
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// If the node is a root node, we have a document we can
|
|
// process.
|
|
|
|
if( pNode->isRootNode())
|
|
{
|
|
if( uiFlags == XFLM_EXCL && ui64NodeId == ui64DocumentId)
|
|
{
|
|
if( RC_BAD( rc = pNode->getNextDocument( this, ppDocumentNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( *ppDocumentNode)
|
|
{
|
|
(*ppDocumentNode)->Release();
|
|
}
|
|
|
|
// No need to do an AddRef on ppDocumentNode - just use the reference
|
|
// from pNode and set pNode to NULL so it won't be released
|
|
|
|
*ppDocumentNode = pNode;
|
|
pNode = NULL;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Need to go to the next node.
|
|
|
|
if( RC_BAD( rc = pBTree->btNextEntry( ucKey, uiKeyLen, &uiKeyLen)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
}
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( pBTree)
|
|
{
|
|
gv_XFlmSysData.pBtPool->btpReturnBtree( &pBTree);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
Notes: This routine assumes that the node has been unlinked. It doesn't
|
|
perform any checks to guarantee that removing the node won't cause
|
|
referential integrity problems.
|
|
******************************************************************************/
|
|
RCODE F_Db::purgeNode(
|
|
FLMUINT uiCollection,
|
|
FLMUINT64 ui64NodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Btree * pBTree = NULL;
|
|
FLMUINT uiKeyLen;
|
|
FLMBYTE ucKey[ FLM_MAX_NUM_BUF_SIZE];
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
// Make sure we're in an update transaction
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Remove the node from the collection
|
|
|
|
if( RC_BAD( rc = getCachedBTree( uiCollection, &pBTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiKeyLen = sizeof( ucKey);
|
|
if( RC_BAD( rc = flmNumber64ToStorage( ui64NodeId,
|
|
&uiKeyLen, ucKey, FALSE, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = pBTree->btRemoveEntry( ucKey, uiKeyLen)))
|
|
{
|
|
if( rc != NE_XFLM_NOT_FOUND)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Item may not have been flushed from cache yet
|
|
|
|
rc = NE_XFLM_OK;
|
|
}
|
|
|
|
// Remove the node from the cache
|
|
|
|
gv_XFlmSysData.pNodeCacheMgr->removeNode( this, uiCollection, ui64NodeId);
|
|
|
|
Exit:
|
|
|
|
if( pBTree)
|
|
{
|
|
pBTree->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
if( bMustAbortOnError)
|
|
{
|
|
setMustAbortTrans( rc);
|
|
}
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::documentDone(
|
|
FLMUINT uiCollection,
|
|
FLMUINT64 ui64DocId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pNode = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
F_Rfl * pRfl = m_pDatabase->m_pRfl;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !m_pDatabase->m_DocumentList.isNodeInList( uiCollection, ui64DocId, 0))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( uiCollection == XFLM_DICT_COLLECTION)
|
|
{
|
|
FLMUINT uiDictDefType;
|
|
|
|
if( RC_BAD( rc = dictDocumentDone( ui64DocId, FALSE, &uiDictDefType)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If this is an encryption definition, we need to log the encryption
|
|
// key
|
|
|
|
if( uiDictDefType == ELM_ENCDEF_TAG && !(m_uiFlags & FDB_REPLAYING_RFL))
|
|
{
|
|
FLMBYTE ucDynaBuf[ 64];
|
|
F_DynaBuf keyBuffer( ucDynaBuf, sizeof( ucDynaBuf));
|
|
FLMUINT uiKeySize;
|
|
|
|
if( RC_BAD( rc = getNode( uiCollection, ui64DocId,
|
|
XFLM_EXACT, &pNode)))
|
|
{
|
|
RC_UNEXPECTED_ASSERT( rc);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNode->getAttributeValueBinary( this,
|
|
ATTR_ENCRYPTION_KEY_TAG, &keyBuffer)))
|
|
{
|
|
RC_UNEXPECTED_ASSERT( rc);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNode->getAttributeValueUINT( this,
|
|
ATTR_ENCRYPTION_KEY_SIZE_TAG, &uiKeySize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logEncDefKey( this, (FLMUINT)ui64DocId,
|
|
keyBuffer.getBufferPtr(), keyBuffer.getDataLength(), uiKeySize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
}
|
|
}
|
|
|
|
m_pDatabase->m_DocumentList.removeNode( uiCollection, ui64DocId, 0);
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logDocumentDone( this, uiCollection, ui64DocId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::documentDone(
|
|
IF_DOMNode * pDocNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiCollection;
|
|
FLMUINT64 ui64DocId;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDocNode->getCollection( this, &uiCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDocNode->getDocumentId( this, &ui64DocId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = documentDone( uiCollection, ui64DocId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::import(
|
|
IF_IStream * ifpStream,
|
|
FLMUINT uiCollection,
|
|
IF_DOMNode * pNodeToLinkTo,
|
|
eNodeInsertLoc eInsertLoc,
|
|
XFLM_IMPORT_STATS * pImportStats)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_XMLImport xmlImport;
|
|
F_DOMNode * pNode = NULL;
|
|
F_DOMNode * pNewNode = NULL;
|
|
|
|
if( RC_BAD( rc = xmlImport.setup()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pNode = (F_DOMNode *)pNodeToLinkTo) != NULL)
|
|
{
|
|
pNode->AddRef();
|
|
}
|
|
|
|
for( ;;)
|
|
{
|
|
if( RC_BAD( rc = xmlImport.import( ifpStream, this, uiCollection,
|
|
FLM_XML_COMPRESS_WHITESPACE_FLAG |
|
|
FLM_XML_TRANSLATE_ESC_FLAG |
|
|
FLM_XML_EXTEND_DICT_FLAG, pNode, eInsertLoc,
|
|
&pNewNode, pImportStats)))
|
|
{
|
|
if( rc == NE_XFLM_EOF_HIT)
|
|
{
|
|
rc = NE_XFLM_OK;
|
|
break;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = documentDone( pNewNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If pNode is NULL, we are creating separate documents
|
|
// and pNode should remain NULL. Otherwise, it should be
|
|
// set to the newly created node, and all subsequent trees
|
|
// should be linked as next siblings after this one.
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
pNode = pNewNode;
|
|
|
|
// No need to do pNode->AddRef() and pNewNode->Release() since
|
|
// there is already a reference on pNewNode.
|
|
|
|
pNewNode = NULL;
|
|
eInsertLoc = XFLM_NEXT_SIB;
|
|
}
|
|
else
|
|
{
|
|
pNewNode->Release();
|
|
pNewNode = NULL;
|
|
}
|
|
|
|
xmlImport.reset();
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
if( pNewNode)
|
|
{
|
|
pNewNode->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::importDocument(
|
|
IF_IStream * ifpStream,
|
|
FLMUINT uiCollection,
|
|
IF_DOMNode ** ppDoc,
|
|
XFLM_IMPORT_STATS * pImportStats)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_XMLImport xmlImport;
|
|
F_DOMNode * pNode = NULL;
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->AddRef();
|
|
}
|
|
|
|
if( RC_BAD( rc = xmlImport.setup()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = xmlImport.import( ifpStream, this, uiCollection,
|
|
FLM_XML_COMPRESS_WHITESPACE_FLAG |
|
|
FLM_XML_TRANSLATE_ESC_FLAG |
|
|
FLM_XML_EXTEND_DICT_FLAG, NULL, XFLM_LAST_CHILD, &pNode, pImportStats)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = documentDone( pNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ppDoc)
|
|
{
|
|
if( *ppDoc)
|
|
{
|
|
(*ppDoc)->Release();
|
|
}
|
|
|
|
*ppDoc = pNode;
|
|
pNode = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pNode)
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::createElemOrAttrDef(
|
|
FLMBOOL bElement,
|
|
FLMBOOL bUnicode,
|
|
const void * pvNamespaceURI,
|
|
const void * pvLocalName,
|
|
FLMUINT uiDataType,
|
|
FLMBOOL bUniqueChildElms,
|
|
FLMUINT * puiNameId,
|
|
F_DOMNode ** ppDocumentNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pDoc = NULL;
|
|
F_DOMNode * pAttr = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = createRootNode( XFLM_DICT_COLLECTION,
|
|
bElement ? ELM_ELEMENT_TAG : ELM_ATTRIBUTE_TAG, ELEMENT_NODE, &pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pvNamespaceURI)
|
|
{
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_TARGET_NAMESPACE_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bUnicode)
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUnicode(
|
|
this, (FLMUNICODE *)pvNamespaceURI)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvNamespaceURI)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pDoc->createAttribute( this, ATTR_NAME_TAG,
|
|
(IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bUnicode)
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUnicode( this, (FLMUNICODE *)pvLocalName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvLocalName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( puiNameId && *puiNameId)
|
|
{
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->setUINT( this, *puiNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_TYPE_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->setUTF8( this,
|
|
(const FLMBYTE *)fdictGetDataTypeStr( uiDataType))))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bUniqueChildElms && bElement)
|
|
{
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_UNIQUE_SUB_ELEMENTS_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)"true")))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = documentDone( pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( puiNameId)
|
|
{
|
|
if( RC_BAD( rc = pDoc->getAttribute( this, ATTR_DICT_NUMBER_TAG,
|
|
(IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->getUINT( this, puiNameId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( ppDocumentNode)
|
|
{
|
|
if( (*ppDocumentNode))
|
|
{
|
|
(*ppDocumentNode)->Release();
|
|
}
|
|
|
|
*ppDocumentNode = pDoc;
|
|
pDoc = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pDoc)
|
|
{
|
|
pDoc->Release();
|
|
}
|
|
|
|
if( pAttr)
|
|
{
|
|
flmAssert( pAttr->m_refCnt <= 2);
|
|
pAttr->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = transCommit();
|
|
}
|
|
}
|
|
else if( RC_BAD( rc))
|
|
{
|
|
setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::createPrefixDef(
|
|
FLMBOOL bUnicode,
|
|
const void * pvPrefixName,
|
|
FLMUINT * puiPrefixNumber)
|
|
{
|
|
F_DOMNode * pDoc = NULL;
|
|
F_DOMNode * pAttr = NULL;
|
|
F_DOMNode * pNumAttr = NULL;
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = createRootNode( XFLM_DICT_COLLECTION,
|
|
ELM_PREFIX_TAG, ELEMENT_NODE, &pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDoc->createAttribute( this, ATTR_NAME_TAG,
|
|
(IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bUnicode)
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUnicode( this, (FLMUNICODE *)pvPrefixName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvPrefixName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Create the prefix number attribute if passed in.
|
|
|
|
if( puiPrefixNumber && *puiPrefixNumber)
|
|
{
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pNumAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNumAttr->setUINT( this, *puiPrefixNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = documentDone( pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Change the modes on the definition so that the name cannot be modified
|
|
// and the definition cannot be deleted. This needs to be done after
|
|
// calling documentDone() because it sets the flags on the nodes of the
|
|
// definition according to a set of default rules that do not correspond
|
|
// to what we need to have in this case.
|
|
|
|
if( RC_BAD( rc = pAttr->addModeFlags(
|
|
this, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( puiPrefixNumber)
|
|
{
|
|
if( RC_BAD( rc = pDoc->getAttribute( this, ATTR_DICT_NUMBER_TAG,
|
|
(IF_DOMNode **)&pNumAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pNumAttr->getUINT( this, puiPrefixNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pDoc)
|
|
{
|
|
pDoc->Release();
|
|
}
|
|
|
|
if( pAttr)
|
|
{
|
|
pAttr->Release();
|
|
}
|
|
|
|
if( pNumAttr)
|
|
{
|
|
pNumAttr->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = transCommit();
|
|
}
|
|
}
|
|
else if( RC_BAD( rc))
|
|
{
|
|
setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::createEncDef(
|
|
FLMBOOL bUnicode,
|
|
const void * pvEncType,
|
|
const void * pvEncName,
|
|
FLMUINT uiKeySize,
|
|
FLMUINT * puiEncDefNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_DOMNode * pDoc = NULL;
|
|
F_DOMNode * pAttr = NULL;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = createRootNode( XFLM_DICT_COLLECTION,
|
|
ELM_ENCDEF_TAG, ELEMENT_NODE, &pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDoc->createAttribute( this, ATTR_NAME_TAG,
|
|
(IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bUnicode)
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUnicode( this, (FLMUNICODE *)pvEncName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvEncName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Create the encdef id attribute if passed in.
|
|
|
|
if( puiEncDefNumber && *puiEncDefNumber)
|
|
{
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->setUINT( this, *puiEncDefNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Create the algorithm attribute
|
|
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_TYPE_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bUnicode)
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUnicode( this, (FLMUNICODE *)pvEncType)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvEncType)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Create the key size attribute
|
|
|
|
if( uiKeySize)
|
|
{
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_ENCRYPTION_KEY_SIZE_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->setUINT( this, uiKeySize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Call documentDone to complete it all.
|
|
|
|
if( RC_BAD( rc = documentDone( pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( puiEncDefNumber)
|
|
{
|
|
if( RC_BAD( rc = pDoc->getAttribute( this, ATTR_DICT_NUMBER_TAG,
|
|
(IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->getUINT( this, puiEncDefNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pDoc)
|
|
{
|
|
pDoc->Release();
|
|
}
|
|
|
|
if( pAttr)
|
|
{
|
|
pAttr->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = transCommit();
|
|
}
|
|
}
|
|
else if( RC_BAD( rc))
|
|
{
|
|
setMustAbortTrans( rc);
|
|
}
|
|
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_Db::getPrefixId(
|
|
const FLMUNICODE * puzPrefixName,
|
|
FLMUINT * puiPrefixNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pDict->getPrefixId(
|
|
this, puzPrefixName, puiPrefixNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_Db::getPrefixId(
|
|
const char * pszPrefixName,
|
|
FLMUINT * puiPrefixNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pDict->getPrefixId(
|
|
this, pszPrefixName, puiPrefixNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_Db::getEncDefId(
|
|
const char * pszEncDefName,
|
|
FLMUINT * puiEncDefNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pDict->getEncDefId( this,
|
|
pszEncDefName, puiEncDefNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
*****************************************************************************/
|
|
RCODE FLMAPI F_Db::getEncDefId(
|
|
const FLMUNICODE * puzEncDefName,
|
|
FLMUINT * puiEncDefNumber)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_READ_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pDict->getEncDefId(
|
|
this, puzEncDefName, puiEncDefNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
transAbort();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc: Create a new c ollection definition in the dictionary.
|
|
******************************************************************************/
|
|
RCODE F_Db::createCollectionDef(
|
|
FLMBOOL bUnicode,
|
|
const void * pvCollectionName,
|
|
FLMUINT * puiCollectionNumber,
|
|
FLMUINT uiEncNumber)
|
|
{
|
|
F_DOMNode * pDoc = NULL;
|
|
F_DOMNode * pAttr = NULL;
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// First, create the root element to hold the collection definition
|
|
|
|
if( RC_BAD( rc = createRootNode( XFLM_DICT_COLLECTION,
|
|
ELM_COLLECTION_TAG, ELEMENT_NODE, &pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Create the collection name attruibute
|
|
|
|
if( RC_BAD( rc = pDoc->createAttribute(
|
|
this, ATTR_NAME_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bUnicode)
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUnicode(
|
|
this, (FLMUNICODE *)pvCollectionName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pAttr->setUTF8( this, (FLMBYTE *)pvCollectionName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Create the collection number attribute if passed in.
|
|
|
|
if( puiCollectionNumber && *puiCollectionNumber)
|
|
{
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->setUINT( this, *puiCollectionNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( uiEncNumber)
|
|
{
|
|
if( RC_BAD( rc = pDoc->createAttribute( this,
|
|
ATTR_ENCRYPTION_ID_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->setUINT( this, uiEncNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = documentDone( pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( puiCollectionNumber)
|
|
{
|
|
if( RC_BAD( rc = pDoc->getAttribute(
|
|
this, ATTR_DICT_NUMBER_TAG, (IF_DOMNode **)&pAttr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttr->getUINT( this, puiCollectionNumber)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = transCommit();
|
|
}
|
|
}
|
|
|
|
if( pDoc)
|
|
{
|
|
pDoc->Release();
|
|
}
|
|
|
|
if( pAttr)
|
|
{
|
|
pAttr->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::flushDirtyNodes( void)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_CachedNode * pNode;
|
|
F_Btree * pBtree = NULL;
|
|
FLMUINT uiRflToken = 0;
|
|
FLMUINT uiCollection = 0;
|
|
|
|
if( !m_uiDirtyNodeCount)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
m_pDatabase->m_pRfl->disableLogging( &uiRflToken);
|
|
|
|
// All of the dirty nodes should be at the front of the list.
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
while ((pNode = m_pDatabase->m_pFirstNode) != NULL)
|
|
{
|
|
if( !pNode->nodeIsDirty())
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Flushing the node should remove it from the front of the list.
|
|
// Need to increment the use count on the node to prevent it from
|
|
// being moved while we are flushing it to disk.
|
|
|
|
pNode->incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
|
|
if( uiCollection != pNode->getCollection())
|
|
{
|
|
if( pBtree)
|
|
{
|
|
pBtree->Release();
|
|
}
|
|
|
|
uiCollection = pNode->getCollection();
|
|
if( RC_BAD( rc = getCachedBTree( uiCollection, &pBtree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
rc = flushNode( pBtree, pNode);
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
pNode->decrNodeUseCount();
|
|
|
|
if( rc == NE_XFLM_NOT_FOUND)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
flmAssert( !m_uiDirtyNodeCount);
|
|
|
|
Exit:
|
|
|
|
if( uiRflToken)
|
|
{
|
|
m_pDatabase->m_pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( pBtree)
|
|
{
|
|
pBtree->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Db::flushDirtyNode(
|
|
F_CachedNode * pNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bMutexLocked = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
F_Btree * pBTree = NULL;
|
|
|
|
m_pDatabase->m_pRfl->disableLogging( &uiRflToken);
|
|
|
|
if( !pNode->nodeIsDirty())
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Get a B-Tree object
|
|
|
|
if( RC_BAD( rc = getCachedBTree( pNode->getCollection(), &pBTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
bMutexLocked = TRUE;
|
|
|
|
pNode->incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
bMutexLocked = FALSE;
|
|
|
|
rc = flushNode( pBTree, pNode);
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
bMutexLocked = TRUE;
|
|
|
|
pNode->decrNodeUseCount();
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( uiRflToken)
|
|
{
|
|
m_pDatabase->m_pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bMutexLocked)
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
}
|
|
|
|
if( pBTree)
|
|
{
|
|
pBTree->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_Database::startPendingInput(
|
|
FLMUINT uiPendingType,
|
|
F_CachedNode * pPendingNode)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
|
|
if( m_pPendingInput)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_INPUT_PENDING);
|
|
goto Exit;
|
|
}
|
|
|
|
// Not supported on element nodes
|
|
|
|
if( pPendingNode->getNodeType() == ELEMENT_NODE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
|
|
m_uiPendingType = uiPendingType;
|
|
m_pPendingInput = pPendingNode;
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
m_pPendingInput->incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
m_uiUpdCharCount = 0;
|
|
m_bUpdFirstBuf = TRUE;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
void F_Database::endPendingInput( void)
|
|
{
|
|
if( m_pPendingInput)
|
|
{
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
m_pPendingInput->decrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
m_pPendingInput = NULL;
|
|
}
|
|
|
|
if( m_pPendingBTree)
|
|
{
|
|
gv_XFlmSysData.pBtPool->btpReturnBtree( &m_pPendingBTree);
|
|
m_pPendingBTree = NULL;
|
|
}
|
|
|
|
m_uiPendingType = XFLM_NODATA_TYPE;
|
|
m_bUpdFirstBuf = TRUE;
|
|
m_uiUpdByteCount = 0;
|
|
m_uiUpdCharCount = 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::createAttribute(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
F_AttrItem ** ppAttrItem)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem = NULL;
|
|
FLMUINT uiInsertPos;
|
|
|
|
// Attribute should not exist
|
|
|
|
if (getAttribute( uiAttrNameId, &uiInsertPos) != NULL)
|
|
{
|
|
flmAssert( 0);
|
|
}
|
|
else
|
|
{
|
|
|
|
// Logging should be done by the caller
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
// Allocate the new attribute
|
|
|
|
if( RC_BAD( rc = allocAttribute( pDb, uiAttrNameId, NULL, uiInsertPos,
|
|
&pAttrItem, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( ppAttrItem)
|
|
{
|
|
*ppAttrItem = pAttrItem;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
F_AttrItem * F_CachedNode::getAttribute(
|
|
FLMUINT uiAttrNameId,
|
|
FLMUINT * puiInsertPos)
|
|
{
|
|
FLMUINT uiLoop;
|
|
F_AttrItem * pAttrItem = NULL;
|
|
FLMUINT uiTblSize;
|
|
FLMUINT uiLow;
|
|
FLMUINT uiMid;
|
|
FLMUINT uiHigh;
|
|
FLMUINT uiTblNameId;
|
|
|
|
if (!m_uiAttrCount)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
// If the attribute count is <= 4, do a sequential search through
|
|
// the array. Otherwise, do a binary search.
|
|
|
|
if ((uiTblSize = m_uiAttrCount) <= 4)
|
|
{
|
|
for (uiLoop = 0; uiLoop < m_uiAttrCount; uiLoop++)
|
|
{
|
|
pAttrItem = m_ppAttrList [uiLoop];
|
|
if (pAttrItem->m_uiNameId == uiAttrNameId)
|
|
{
|
|
break;
|
|
}
|
|
else if (pAttrItem->m_uiNameId > uiAttrNameId)
|
|
{
|
|
pAttrItem = NULL;
|
|
break;
|
|
}
|
|
}
|
|
if (uiLoop == m_uiAttrCount)
|
|
{
|
|
pAttrItem = NULL;
|
|
}
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = uiLoop;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiHigh = --uiTblSize;
|
|
uiLow = 0;
|
|
for (;;)
|
|
{
|
|
uiMid = (uiLow + uiHigh) / 2;
|
|
uiTblNameId = m_ppAttrList [uiMid]->m_uiNameId;
|
|
if (uiTblNameId == uiAttrNameId)
|
|
{
|
|
// Found Match
|
|
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = uiMid;
|
|
}
|
|
pAttrItem = m_ppAttrList [uiMid];
|
|
goto Exit;
|
|
}
|
|
|
|
// Check if we are done
|
|
|
|
if (uiLow >= uiHigh)
|
|
{
|
|
// Done, item not found
|
|
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = (uiAttrNameId < uiTblNameId)
|
|
? uiMid
|
|
: uiMid + 1;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
if (uiAttrNameId < uiTblNameId)
|
|
{
|
|
if (uiMid == 0)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiHigh = uiMid - 1;
|
|
}
|
|
else
|
|
{
|
|
if (uiMid == uiTblSize)
|
|
{
|
|
if (puiInsertPos)
|
|
{
|
|
*puiInsertPos = uiMid + 1;
|
|
}
|
|
goto Exit;
|
|
}
|
|
uiLow = uiMid + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( pAttrItem);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::getPrevSiblingNode(
|
|
FLMUINT uiCurrentNameId,
|
|
IF_DOMNode ** ppSib)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
F_DOMNode * pAttr = NULL;
|
|
|
|
if( (pAttrItem = getPrevSibling( uiCurrentNameId)) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttr)))
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttr->m_uiAttrNameId = pAttrItem->m_uiNameId;
|
|
pAttr->m_pCachedNode = this;
|
|
incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
|
|
if( ppSib)
|
|
{
|
|
if( *ppSib)
|
|
{
|
|
(*ppSib)->Release();
|
|
}
|
|
|
|
*ppSib = (IF_DOMNode *)pAttr;
|
|
pAttr = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttr)
|
|
{
|
|
pAttr->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::getNextSiblingNode(
|
|
FLMUINT uiCurrentNameId,
|
|
IF_DOMNode ** ppSib)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
F_DOMNode * pAttr = NULL;
|
|
|
|
if( (pAttrItem = getNextSibling( uiCurrentNameId)) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->allocDOMNode( &pAttr)))
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttr->m_uiAttrNameId = pAttrItem->m_uiNameId;
|
|
pAttr->m_pCachedNode = this;
|
|
incrNodeUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
|
|
if( ppSib)
|
|
{
|
|
if( *ppSib)
|
|
{
|
|
(*ppSib)->Release();
|
|
}
|
|
|
|
*ppSib = (IF_DOMNode *)pAttr;
|
|
pAttr = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pAttr)
|
|
{
|
|
pAttr->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::allocAttribute(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
F_AttrItem * pCopyFromItem,
|
|
FLMUINT uiInsertPos,
|
|
F_AttrItem ** ppAttrItem,
|
|
FLMBOOL bMutexAlreadyLocked)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrElmInfo defInfo;
|
|
F_AttrItem * pAttrItem = NULL;
|
|
FLMUINT uiSize;
|
|
FLMBOOL bMutexLocked = FALSE;
|
|
|
|
if( RC_BAD( rc = pDb->m_pDict->getAttribute(
|
|
pDb, uiAttrNameId, &defInfo)))
|
|
{
|
|
flmAssert( 0);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !bMutexAlreadyLocked)
|
|
{
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
bMutexLocked = TRUE;
|
|
}
|
|
|
|
if( (pAttrItem = new F_AttrItem) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_MEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pCopyFromItem)
|
|
{
|
|
pAttrItem->copyFrom( pCopyFromItem);
|
|
}
|
|
else
|
|
{
|
|
if( defInfo.getFlags() & ATTR_ELM_NS_DECL)
|
|
{
|
|
pAttrItem->m_uiFlags |= FDOM_NAMESPACE_DECL;
|
|
}
|
|
}
|
|
|
|
// Find where this thing goes in the attribute list
|
|
// If we are copying, we don't need to resize the list as it will
|
|
// already be the correct size.
|
|
|
|
if (!pCopyFromItem)
|
|
{
|
|
if (RC_BAD( rc = resizeAttrList( m_uiAttrCount + 1, bMutexLocked)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// NOTE: m_uiAttrCount will have been incremented to accommodate
|
|
// the new attribute.
|
|
|
|
// Move everything above the [uiInsertPos] slot up. Remember, no need to
|
|
// preserve the item at [m_uiAttrCount - 1], because we just increased
|
|
// the size of the array, and there is nothing there right now.
|
|
|
|
if (uiInsertPos < m_uiAttrCount - 1)
|
|
{
|
|
f_memmove( &m_ppAttrList [uiInsertPos + 1],
|
|
&m_ppAttrList [uiInsertPos],
|
|
sizeof( F_AttrItem *) * (m_uiAttrCount - uiInsertPos - 1));
|
|
}
|
|
}
|
|
m_ppAttrList [uiInsertPos] = pAttrItem;
|
|
|
|
pAttrItem->m_pCachedNode = this;
|
|
pAttrItem->m_uiDataType = defInfo.getDataType();
|
|
pAttrItem->m_uiNameId = uiAttrNameId;
|
|
*ppAttrItem = pAttrItem;
|
|
|
|
uiSize = pAttrItem->memSize();
|
|
m_uiTotalAttrSize += uiSize;
|
|
|
|
if (m_ui64HighTransId != FLM_MAX_UINT64)
|
|
{
|
|
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiOldVerBytes += uiSize;
|
|
}
|
|
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiByteCount += uiSize;
|
|
|
|
// Set to NULL so it won't get deleted below.
|
|
|
|
pAttrItem = NULL;
|
|
|
|
Exit:
|
|
|
|
if (pAttrItem)
|
|
{
|
|
delete pAttrItem;
|
|
}
|
|
|
|
if( bMutexLocked)
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::freeAttribute(
|
|
F_AttrItem * pAttrItem,
|
|
FLMUINT uiPos)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bMutexLocked = FALSE;
|
|
|
|
// Move everything above the [uiPos] slot down.
|
|
|
|
if (uiPos < m_uiAttrCount - 1)
|
|
{
|
|
f_memmove( &m_ppAttrList [uiPos],
|
|
&m_ppAttrList [uiPos + 1],
|
|
sizeof( F_AttrItem *) * (m_uiAttrCount - uiPos - 1));
|
|
}
|
|
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
bMutexLocked = TRUE;
|
|
if (RC_BAD( rc = resizeAttrList( m_uiAttrCount - 1, bMutexLocked)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
delete pAttrItem;
|
|
|
|
Exit:
|
|
|
|
if (bMutexLocked)
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::setNumber64(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
FLMUINT64 ui64Value,
|
|
FLMBOOL bNeg,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
FLMUINT uiValLen = 0;
|
|
FLMUINT uiEncryptedLen;
|
|
FLMBYTE ucNumBuf[ 32];
|
|
|
|
// Logging should be done by the caller
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
// Get a pointer to the attribute list item
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
if( RC_BAD( rc = createAttribute( pDb, uiAttrNameId, &pAttrItem)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pAttrItem->m_uiFlags & FDOM_READ_ONLY)
|
|
{
|
|
rc = RC_SET( NE_XFLM_READ_ONLY);
|
|
goto Exit;
|
|
}
|
|
pAttrItem->m_uiFlags &= ~(FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
|
|
}
|
|
|
|
pAttrItem->m_ui64QuickVal = ui64Value;
|
|
|
|
if( bNeg)
|
|
{
|
|
pAttrItem->m_uiFlags |= FDOM_SIGNED_QUICK_VAL;
|
|
}
|
|
else
|
|
{
|
|
pAttrItem->m_uiFlags |= FDOM_UNSIGNED_QUICK_VAL;
|
|
}
|
|
|
|
switch( pAttrItem->m_uiDataType)
|
|
{
|
|
case XFLM_NUMBER_TYPE:
|
|
{
|
|
if( ui64Value <= 0x7F && !uiEncDefId)
|
|
{
|
|
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, 0, 1, FALSE,
|
|
FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*(pAttrItem->getAttrDataPtr()) = (FLMBYTE)ui64Value;
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
uiValLen = sizeof( ucNumBuf);
|
|
if( RC_BAD( rc = flmNumber64ToStorage(
|
|
ui64Value, &uiValLen, ucNumBuf, bNeg, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case XFLM_TEXT_TYPE:
|
|
{
|
|
FLMBYTE * pucSen;
|
|
FLMUINT uiSenLen;
|
|
|
|
if( bNeg)
|
|
{
|
|
ucNumBuf[ 1] = '-';
|
|
f_ui64toa( ui64Value, (char *)&ucNumBuf[ 2]);
|
|
}
|
|
else
|
|
{
|
|
f_ui64toa( ui64Value, (char *)&ucNumBuf[ 1]);
|
|
}
|
|
|
|
uiValLen = f_strlen( (const char *)&ucNumBuf[ 1]);
|
|
pucSen = &ucNumBuf [0];
|
|
uiSenLen = f_encodeSEN( uiValLen, &pucSen, (FLMUINT)0);
|
|
flmAssert( uiSenLen == 1);
|
|
uiValLen += uiSenLen + 1;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_BAD_DATA_TYPE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, uiEncDefId,
|
|
uiValLen, TRUE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiValLen)
|
|
{
|
|
f_memcpy( pAttrItem->getAttrDataPtr(), ucNumBuf, uiValLen);
|
|
|
|
if( uiEncDefId)
|
|
{
|
|
if( RC_BAD( rc = pDb->encryptData( uiEncDefId,
|
|
pAttrItem->getAttrIVPtr(), pAttrItem->getAttrDataPtr(),
|
|
pAttrItem->getAttrDataBufferSize(), uiValLen, &uiEncryptedLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pAttrItem->m_uiPayloadLen = 0;
|
|
}
|
|
|
|
pAttrItem->m_uiDecryptedDataLen = uiValLen;
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::getNumber64(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
FLMUINT64 * pui64Value,
|
|
FLMBOOL * pbNeg)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMBOOL bNeg;
|
|
FLMUINT64 ui64Value;
|
|
F_AttrItem * pAttrItem;
|
|
IF_PosIStream * pIStream = NULL;
|
|
F_NodeBufferIStream bufferIStream;
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
else if( pAttrItem->m_uiFlags & FDOM_UNSIGNED_QUICK_VAL)
|
|
{
|
|
*pbNeg = FALSE;
|
|
*pui64Value = pAttrItem->m_ui64QuickVal;
|
|
}
|
|
else if( pAttrItem->m_uiFlags & FDOM_SIGNED_QUICK_VAL)
|
|
{
|
|
*pbNeg = TRUE;
|
|
*pui64Value = pAttrItem->m_ui64QuickVal;
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = getIStream( pDb, uiAttrNameId, &bufferIStream, &pIStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmReadStorageAsNumber(
|
|
pIStream, pAttrItem->m_uiDataType, &ui64Value, &bNeg)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*pui64Value = ui64Value;
|
|
*pbNeg = bNeg;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::setBinary(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
const void * pvValue,
|
|
FLMUINT uiValueLen,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
FLMUINT uiDecryptedValLen = 0;
|
|
FLMUINT uiEncryptedLen;
|
|
|
|
// Logging should be done by the caller
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
// Get a pointer to the attribute list item
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
if( RC_BAD( rc = createAttribute( pDb, uiAttrNameId, &pAttrItem)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pAttrItem->m_uiFlags & FDOM_READ_ONLY)
|
|
{
|
|
rc = RC_SET( NE_XFLM_READ_ONLY);
|
|
goto Exit;
|
|
}
|
|
pAttrItem->m_uiFlags &= ~(FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
|
|
}
|
|
|
|
switch( pAttrItem->m_uiDataType)
|
|
{
|
|
case XFLM_BINARY_TYPE:
|
|
{
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, uiEncDefId,
|
|
uiValueLen, TRUE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiValueLen)
|
|
{
|
|
f_memcpy( pAttrItem->getAttrDataPtr(), pvValue, uiValueLen);
|
|
|
|
if( uiEncDefId)
|
|
{
|
|
uiDecryptedValLen = uiValueLen;
|
|
if( RC_BAD( rc = pDb->encryptData( uiEncDefId,
|
|
pAttrItem->getAttrIVPtr(), pAttrItem->getAttrDataPtr(),
|
|
pAttrItem->getAttrDataBufferSize(), uiValueLen, &uiEncryptedLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( uiEncryptedLen == pAttrItem->getAttrDataBufferSize());
|
|
}
|
|
}
|
|
|
|
pAttrItem->m_uiDecryptedDataLen = uiValueLen;
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::getBinary(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
void * pvBuffer,
|
|
FLMUINT uiBufferLen,
|
|
FLMUINT * puiDataLen)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
IF_PosIStream * pIStream = NULL;
|
|
F_NodeBufferIStream bufferIStream;
|
|
|
|
// If a NULL buffer is passed in, just return the
|
|
// data length
|
|
|
|
if( !pvBuffer)
|
|
{
|
|
rc = getDataLength( uiAttrNameId, puiDataLen);
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( !pAttrItem->m_uiEncDefId)
|
|
{
|
|
FLMUINT uiCopySize = f_min( uiBufferLen,
|
|
pAttrItem->getAttrDataLength());
|
|
|
|
if( uiCopySize)
|
|
{
|
|
f_memcpy( pvBuffer, pAttrItem->getAttrDataPtr(), uiCopySize);
|
|
}
|
|
|
|
if( puiDataLen)
|
|
{
|
|
*puiDataLen = uiCopySize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = getIStream( pDb, uiAttrNameId, &bufferIStream, &pIStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmReadStorageAsBinary( pIStream,
|
|
pvBuffer, uiBufferLen, 0, puiDataLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pIStream)
|
|
{
|
|
pIStream->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::setUTF8(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
const void * pvValue,
|
|
FLMUINT uiNumBytesInValue,
|
|
FLMUINT uiNumCharsInValue,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
FLMUINT uiValLen = 0;
|
|
FLMUINT uiDecryptedValLen = 0;
|
|
FLMUINT uiEncryptedLen;
|
|
FLMUINT uiSenLen;
|
|
FLMBYTE * pucValue = (FLMBYTE *)pvValue;
|
|
FLMBOOL bNullTerminate = FALSE;
|
|
|
|
// Logging should be done by the caller
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
// Get a pointer to the attribute list item
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
if( RC_BAD( rc = createAttribute( pDb, uiAttrNameId, &pAttrItem)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pAttrItem->m_uiFlags & FDOM_READ_ONLY)
|
|
{
|
|
rc = RC_SET( NE_XFLM_READ_ONLY);
|
|
goto Exit;
|
|
}
|
|
pAttrItem->m_uiFlags &= ~(FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
|
|
}
|
|
|
|
switch( pAttrItem->m_uiDataType)
|
|
{
|
|
case XFLM_TEXT_TYPE:
|
|
{
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( pvValue && uiNumBytesInValue)
|
|
{
|
|
if( pucValue[ uiNumBytesInValue - 1] != 0)
|
|
{
|
|
bNullTerminate = TRUE;
|
|
}
|
|
|
|
uiSenLen = f_getSENByteCount( uiNumCharsInValue);
|
|
uiValLen = uiNumBytesInValue + uiSenLen + (bNullTerminate ? 1 : 0);
|
|
}
|
|
else
|
|
{
|
|
uiSenLen = 0;
|
|
uiValLen = 0;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, uiEncDefId,
|
|
uiValLen, TRUE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiValLen)
|
|
{
|
|
FLMBYTE * pucTmp = pAttrItem->getAttrDataPtr();
|
|
|
|
f_encodeSENKnownLength( uiNumCharsInValue, uiSenLen, &pucTmp);
|
|
f_memcpy( pucTmp, pucValue, uiNumBytesInValue);
|
|
|
|
if( bNullTerminate)
|
|
{
|
|
pucTmp[ uiNumBytesInValue] = 0;
|
|
}
|
|
|
|
if( uiEncDefId)
|
|
{
|
|
uiDecryptedValLen = uiValLen;
|
|
if( RC_BAD( rc = pDb->encryptData( uiEncDefId,
|
|
pAttrItem->getAttrIVPtr(), pAttrItem->getAttrDataPtr(),
|
|
pAttrItem->getAttrDataBufferSize(), uiValLen, &uiEncryptedLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
pAttrItem->m_uiDecryptedDataLen = uiValLen;
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::setStorageValue(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
const void * pvValue,
|
|
FLMUINT uiValueLen,
|
|
FLMUINT uiEncDefId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
FLMUINT uiDecryptedValLen = 0;
|
|
FLMUINT uiEncryptedLen;
|
|
|
|
// Logging should be done by the caller
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
// Get a pointer to the attribute list item
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
if( RC_BAD( rc = createAttribute( pDb, uiAttrNameId, &pAttrItem)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pAttrItem->m_uiFlags &= ~(FDOM_UNSIGNED_QUICK_VAL | FDOM_SIGNED_QUICK_VAL);
|
|
}
|
|
|
|
if( pAttrItem->m_uiDataType == XFLM_UNKNOWN_TYPE)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAttrItem->setupAttribute( pDb, uiEncDefId,
|
|
uiValueLen, TRUE, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( uiValueLen)
|
|
{
|
|
f_memcpy( pAttrItem->getAttrDataPtr(), pvValue, uiValueLen);
|
|
|
|
if( uiEncDefId)
|
|
{
|
|
uiDecryptedValLen = uiValueLen;
|
|
if( RC_BAD( rc = pDb->encryptData( uiEncDefId,
|
|
pAttrItem->getAttrIVPtr(), pAttrItem->getAttrDataPtr(),
|
|
pAttrItem->getAttrDataBufferSize(), uiValueLen, &uiEncryptedLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
flmAssert( uiEncryptedLen == pAttrItem->getAttrDataBufferSize());
|
|
}
|
|
}
|
|
|
|
pAttrItem->m_uiDecryptedDataLen = uiValueLen;
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
pDb->setMustAbortTrans( rc);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::addModeFlags(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
FLMUINT uiFlags)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
|
|
F_UNREFERENCED_PARM( pDb);
|
|
|
|
// Logging should be done by the caller
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttrItem->m_uiFlags |= uiFlags;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::removeModeFlags(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
FLMUINT uiFlags)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
|
|
F_UNREFERENCED_PARM( pDb);
|
|
|
|
// Logging should be done by the caller
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttrItem->m_uiFlags &= ~uiFlags;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Desc:
|
|
******************************************************************************/
|
|
RCODE F_CachedNode::setPrefixId(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
FLMUINT uiPrefixId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
|
|
F_UNREFERENCED_PARM( pDb);
|
|
|
|
// Logging should be done by the caller
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
pAttrItem->m_uiPrefixId = uiPrefixId;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE F_CachedNode::getIStream(
|
|
F_Db * pDb,
|
|
FLMUINT uiAttrNameId,
|
|
F_NodeBufferIStream * pStackStream,
|
|
IF_PosIStream ** ppIStream,
|
|
FLMUINT * puiDataType,
|
|
FLMUINT * puiDataLength)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_AttrItem * pAttrItem;
|
|
F_NodeBufferIStream * pNodeBufferIStream = NULL;
|
|
FLMBYTE * pucAllocatedBuffer = NULL;
|
|
|
|
if( (pAttrItem = getAttribute( uiAttrNameId, NULL)) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DOM_NODE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if( pStackStream)
|
|
{
|
|
pNodeBufferIStream = pStackStream;
|
|
pStackStream->AddRef();
|
|
flmAssert( !pStackStream->m_pCachedNode);
|
|
}
|
|
else
|
|
{
|
|
if( (pNodeBufferIStream = f_new F_NodeBufferIStream) == NULL)
|
|
{
|
|
rc = RC_SET( NE_XFLM_MEM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( pAttrItem->m_uiEncDefId)
|
|
{
|
|
flmAssert( pAttrItem->m_uiIVLen);
|
|
|
|
if( RC_BAD( rc = pNodeBufferIStream->open( NULL,
|
|
pAttrItem->getAttrDataBufferSize(), (char **)&pucAllocatedBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->decryptData(
|
|
pAttrItem->m_uiEncDefId, pAttrItem->getAttrIVPtr(),
|
|
pAttrItem->getAttrDataPtr(), pAttrItem->getAttrDataBufferSize(),
|
|
pucAllocatedBuffer, (FLMUINT)pNodeBufferIStream->totalSize())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pNodeBufferIStream->truncate( pAttrItem->getAttrDataLength());
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pNodeBufferIStream->open(
|
|
(const char *)pAttrItem->getAttrDataPtr(),
|
|
pAttrItem->getAttrDataLength())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( !pStackStream)
|
|
{
|
|
pNodeBufferIStream->m_pCachedNode = this;
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
incrNodeUseCount();
|
|
incrStreamUseCount();
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
}
|
|
|
|
if( puiDataType)
|
|
{
|
|
*puiDataType = pAttrItem->m_uiDataType;
|
|
}
|
|
|
|
if( puiDataLength)
|
|
{
|
|
*puiDataLength = (FLMUINT)pNodeBufferIStream->remainingSize();
|
|
}
|
|
|
|
if( *ppIStream)
|
|
{
|
|
(*ppIStream)->Release();
|
|
}
|
|
|
|
*ppIStream = pNodeBufferIStream;
|
|
pNodeBufferIStream = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pNodeBufferIStream)
|
|
{
|
|
pNodeBufferIStream->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE F_AttrItem::resizePayloadBuffer(
|
|
FLMUINT uiTotalNeeded,
|
|
FLMBOOL bMutexAlreadyLocked)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiCurrentSize = m_uiPayloadLen;
|
|
FLMBOOL bMutexLocked = FALSE;
|
|
|
|
if( uiCurrentSize != uiTotalNeeded)
|
|
{
|
|
FLMUINT uiOldSize = memSize();
|
|
FLMUINT uiNewSize;
|
|
FLMUINT uiSize;
|
|
|
|
if( uiTotalNeeded <= sizeof( FLMBYTE *))
|
|
{
|
|
if( uiCurrentSize && uiCurrentSize > sizeof( FLMBYTE *))
|
|
{
|
|
if (!bMutexAlreadyLocked)
|
|
{
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
bMutexLocked = TRUE;
|
|
}
|
|
m_pucPayload -= sizeof( F_AttrItem *);
|
|
gv_XFlmSysData.pNodeCacheMgr->m_pBufAllocator->freeBuf( m_uiPayloadLen +
|
|
sizeof( F_AttrItem *), &m_pucPayload);
|
|
}
|
|
else
|
|
{
|
|
// NOTE: Mutex is NOT locked here, because
|
|
// nothing will be changed that requires the
|
|
// mutex to be locked. Nor will the size
|
|
// change. If the size were to change, we
|
|
// would want to lock the mutex because we
|
|
// would be incrementing/decrementing size
|
|
// counts below.
|
|
|
|
m_pucPayload = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
F_AttrItem * pAttrItem = this;
|
|
|
|
if (!bMutexAlreadyLocked)
|
|
{
|
|
f_mutexLock( gv_XFlmSysData.hNodeCacheMutex);
|
|
bMutexLocked = TRUE;
|
|
}
|
|
|
|
if( uiCurrentSize && uiCurrentSize > sizeof( FLMBYTE *))
|
|
{
|
|
m_pucPayload -= sizeof( F_AttrItem *);
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->m_pBufAllocator->reallocBuf(
|
|
&gv_XFlmSysData.pNodeCacheMgr->m_attrBufferRelocator,
|
|
m_uiPayloadLen + sizeof( F_AttrItem *),
|
|
uiTotalNeeded + sizeof( F_AttrItem *),
|
|
&pAttrItem, sizeof( F_AttrItem *), &m_pucPayload)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = gv_XFlmSysData.pNodeCacheMgr->m_pBufAllocator->allocBuf(
|
|
&gv_XFlmSysData.pNodeCacheMgr->m_attrBufferRelocator,
|
|
uiTotalNeeded + sizeof( F_AttrItem *),
|
|
&pAttrItem, sizeof( F_AttrItem *), &m_pucPayload)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
flmAssert( *((F_AttrItem **)m_pucPayload) == this);
|
|
m_pucPayload += sizeof( F_AttrItem *);
|
|
}
|
|
m_uiPayloadLen = uiTotalNeeded;
|
|
uiNewSize = memSize();
|
|
if (uiNewSize > uiOldSize)
|
|
{
|
|
uiSize = uiNewSize - uiOldSize;
|
|
m_pCachedNode->m_uiTotalAttrSize += uiSize;
|
|
if (m_pCachedNode->m_ui64HighTransId != FLM_MAX_UINT64)
|
|
{
|
|
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiOldVerBytes += uiSize;
|
|
}
|
|
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiByteCount += uiSize;
|
|
}
|
|
else if (uiNewSize < uiOldSize)
|
|
{
|
|
uiSize = uiOldSize - uiNewSize;
|
|
flmAssert( m_pCachedNode->m_uiTotalAttrSize >= uiSize);
|
|
m_pCachedNode->m_uiTotalAttrSize -= uiSize;
|
|
if (m_pCachedNode->m_ui64HighTransId != FLM_MAX_UINT64)
|
|
{
|
|
flmAssert( gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiOldVerBytes >= uiSize);
|
|
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiOldVerBytes -= uiSize;
|
|
}
|
|
flmAssert( gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiByteCount >= uiSize);
|
|
gv_XFlmSysData.pNodeCacheMgr->m_Usage.uiByteCount -= uiSize;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( bMutexLocked)
|
|
{
|
|
f_mutexUnlock( gv_XFlmSysData.hNodeCacheMutex);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE F_AttrItem::setupAttribute(
|
|
F_Db * pDb,
|
|
FLMUINT uiEncDefId,
|
|
FLMUINT uiDataSizeNeeded,
|
|
FLMBOOL bOkToGenerateIV,
|
|
FLMBOOL bMutexAlreadyLocked)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
FLMUINT uiTotalNeeded = uiDataSizeNeeded;
|
|
FLMUINT uiIVLen = 0;
|
|
FLMBOOL bGenerateIV = FALSE;
|
|
F_ENCDEF * pEncDef = NULL;
|
|
|
|
if( uiEncDefId)
|
|
{
|
|
if( RC_BAD( rc = pDb->m_pDict->getEncDef(
|
|
uiEncDefId, &pEncDef)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiIVLen = pEncDef->pCcs->getIVLen();
|
|
flmAssert( uiIVLen == 8 || uiIVLen == 16);
|
|
m_uiEncDefId = uiEncDefId;
|
|
m_uiIVLen = uiIVLen;
|
|
|
|
if( bOkToGenerateIV)
|
|
{
|
|
bGenerateIV = TRUE;
|
|
}
|
|
|
|
uiTotalNeeded += m_uiIVLen +
|
|
(getEncLen( uiDataSizeNeeded) - uiDataSizeNeeded);
|
|
}
|
|
else
|
|
{
|
|
m_uiEncDefId = 0;
|
|
m_uiIVLen = 0;
|
|
}
|
|
|
|
#ifdef FLM_DEBUG
|
|
if( uiEncDefId)
|
|
{
|
|
flmAssert( uiTotalNeeded >= 8 + uiDataSizeNeeded);
|
|
}
|
|
#endif
|
|
|
|
if( RC_BAD( rc = resizePayloadBuffer( uiTotalNeeded, bMutexAlreadyLocked)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( bGenerateIV)
|
|
{
|
|
if( RC_BAD( rc = pEncDef->pCcs->generateIV( uiIVLen, getAttrIVPtr())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FLMAPI F_NodeBufferIStream::open(
|
|
const char * pucBuffer,
|
|
FLMUINT uiLength,
|
|
char ** ppucAllocatedBuffer)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
IF_BufferIStream * pBufferIStream = NULL;
|
|
|
|
if( RC_BAD( rc = FlmAllocBufferIStream( &pBufferIStream)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pBufferIStream->open( pucBuffer,
|
|
uiLength, ppucAllocatedBuffer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_pBufferIStream = pBufferIStream;
|
|
pBufferIStream = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pBufferIStream)
|
|
{
|
|
pBufferIStream->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|