void SetterCommand::undo()
{
   
   int i, size;
   size = tables.size();
   
   // Set back the old values.
   QSqlQuery transBegin("BEGIN TRANSACTION", Database::sqlDatabase());
   QList<QSqlQuery> queries = undoStatements();

   foreach( QSqlQuery q, queries )
   {
      if( ! q.exec() )
         Brewtarget::logE( QString("SetterCommand::undo: %1.\n   \"%2\"").arg(q.lastError().text()).arg(q.lastQuery()) );
   }
   QSqlQuery transEnd("COMMIT", Database::sqlDatabase());
   
   // Emit signals.
   for( i = 0; i < size; ++i )
   {
      queries[i].finish();
      if( notify.at(i) )
         emit objects[i]->changed(props[i],oldValues[i]);
   }
}
void SetterCommand::oldValueTransaction()
{
   QList<QSqlQuery> queries;
   QList<QSqlQuery>::const_iterator qIt, qEnd;
   QString str;

   QList<Brewtarget::DBTable>::const_iterator tableIt, tableEnd;
   QList<QString>::const_iterator colNameIt;
   QList<int>::const_iterator keyIt;
   QList<QVariant>::const_iterator oldValueIt;
   tableIt = tables.constBegin();
   colNameIt = col_names.constBegin();
   keyIt = keys.begin();
   oldValueIt = oldValues.begin();
   
   tableEnd = tables.constEnd();
   QSqlQuery transBegin("BEGIN TRANSACTION", Database::sqlDatabase());
   while( tableIt != tableEnd )
   {
      QSqlQuery q( Database::sqlDatabase() );
      q.setForwardOnly(true);
      str = QString("SELECT `%1` FROM `%2` WHERE id='%3'")
                .arg(*colNameIt)
                .arg(Database::tableNames[*tableIt])
                .arg(*keyIt);
      q.prepare(str);
      queries.append(q);
      q.exec();
      ++tableIt;
      ++colNameIt;
      ++keyIt;
   }
   QSqlQuery transCommit("COMMIT", Database::sqlDatabase());
   
   qEnd = queries.constEnd();
   oldValues.clear();
   for( qIt = queries.constBegin(); qIt != qEnd; ++qIt )
   {
      QSqlQuery q = *qIt;
      if( q.next() )
         oldValues.append(q.record().value(0));
      else
         Brewtarget::logE( QString("SetterCommand::oldValueTransaction: %1.\n   \"%2\"").arg(q.lastError().text()).arg(q.lastQuery()) );
   }
}
/*API~***********************************************************************
Area :	RETRIEVAL
Desc:		Retrieves a key from an index based on a passed-in GEDCOM tree and DRN.
*END************************************************************************/
RCODE	F_Db::keyRetrieve(
    FLMUINT					uiIndex,
    // [IN] Index number.
    IF_DataVector *		ifpSearchKey,
    // [IN] Pointer to the search key.
    FLMUINT					uiFlags,
    // [IN] Flag (XFLM_FIRST, XFLM_LAST, XFLM_EXCL, XFLM_INCL,
    // XFLM_EXACT, XFLM_KEY_EXACT
    IF_DataVector *		ifpFoundKey
    // [OUT] Returns key that was found - may also have data components.
)
{
    RCODE				rc = NE_XFLM_OK;
    IXD *				pIxd = NULL;
    LFILE *			pLFile;
    FLMBYTE *		pucSearchKey = NULL;
    FLMBYTE *		pucFoundKey = NULL;
    void *			pvMark = m_tempPool.poolMark();
    FLMUINT			uiSearchKeyLen = 0;
    FLMUINT			uiFoundKeyLen;
    FLMUINT			uiOriginalFlags;
    F_Btree *		pbtree = NULL;
    FLMUINT			uiDataLen;
    FLMBOOL			bStartedTrans = FALSE;
    FLMUINT			uiIdMatchFlags = uiFlags & (XFLM_MATCH_IDS | XFLM_MATCH_DOC_ID);
    IXKeyCompare	compareObject;
    FLMBOOL			bCompareDocId = FALSE;
    FLMBOOL			bCompareNodeIds = FALSE;
    F_DataVector *	pSearchKey = (F_DataVector *)ifpSearchKey;
    F_DataVector *	pFoundKey = (F_DataVector *)ifpFoundKey;

    // See if the database is being forced to close

    if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
    {
        goto Exit;
    }

    // If we are not in a transaction, we cannot read.

    if (m_eTransType == XFLM_NO_TRANS)
    {
        if( RC_BAD( rc = transBegin( XFLM_READ_TRANS)))
        {
            goto Exit;
        }

        bStartedTrans = TRUE;
    }

    // See if we have a transaction going which should be aborted.

    if( RC_BAD( m_AbortRc))
    {
        rc = RC_SET( NE_XFLM_ABORT_TRANS);
        goto Exit;
    }

    // Allocate key buffers.

    if (pSearchKey)
    {
        if (RC_BAD( rc = m_tempPool.poolAlloc( XFLM_MAX_KEY_SIZE,
                                               (void **)&pucSearchKey)))
        {
            goto Exit;
        }
    }

    if (RC_BAD( rc = m_tempPool.poolAlloc( XFLM_MAX_KEY_SIZE, (void **)&pucFoundKey)))
    {
        goto Exit;
    }

    // Make sure it is a valid index definition

    if (RC_BAD( rc = m_pDict->getIndex( uiIndex, &pLFile, &pIxd)))
    {
        goto Exit;
    }

    if (RC_BAD( rc = flushKeys()))
    {
        goto Exit;
    }

    if (uiFlags & XFLM_FIRST || (!pSearchKey &&
                                 !(uiFlags & XFLM_FIRST) && !(uiFlags & XFLM_LAST)))
    {
        uiOriginalFlags = uiFlags = XFLM_FIRST;
    }
    else if (uiFlags & XFLM_LAST)
    {
        uiOriginalFlags = uiFlags = XFLM_LAST;
    }
    else
    {
        uiOriginalFlags = uiFlags;
        if( !(uiIdMatchFlags & XFLM_MATCH_IDS))
        {
            flmAssert( !(uiFlags & XFLM_KEY_EXACT));
            if (uiFlags & XFLM_EXCL)
            {
                uiFlags = XFLM_EXCL;
            }
            else if (uiFlags & XFLM_EXACT)
            {
                uiOriginalFlags = XFLM_EXACT | XFLM_KEY_EXACT;
                uiFlags = XFLM_INCL;
            }
            else
            {
                uiFlags = XFLM_INCL;
            }
        }
        else
        {
            if (uiFlags & XFLM_EXACT)
            {
                flmAssert( !(uiFlags & XFLM_KEY_EXACT));
                uiFlags = XFLM_EXACT;
            }
            else if (uiFlags & XFLM_EXCL)
            {
                uiFlags = XFLM_EXCL;
            }
            else
            {
                uiFlags = XFLM_INCL;
            }
        }

        if (RC_BAD( rc = pSearchKey->outputKey( pIxd, uiIdMatchFlags,
                                                pucSearchKey, XFLM_MAX_KEY_SIZE, &uiSearchKeyLen, SEARCH_KEY_FLAG)))
        {
            goto Exit;
        }

        // If we are not matching on the IDs and this is an XFLM_EXCL
        // search, tack on a 0xFF for the IDs, which should get us past
        // all keys that match.  We need to turn on the match IDs flags
        // in this case so that the comparison routine will match on the
        // 0xFF.

        if (!uiIdMatchFlags && (uiFlags & XFLM_EXCL))
        {
            pucSearchKey [uiSearchKeyLen++] = 0xFF;
            bCompareDocId = TRUE;
            bCompareNodeIds = TRUE;
        }
        else
        {
            if (uiIdMatchFlags & XFLM_MATCH_IDS)
            {
                bCompareNodeIds = TRUE;
                bCompareDocId = TRUE;
            }
            else if (uiIdMatchFlags & XFLM_MATCH_DOC_ID)
            {
                bCompareDocId = TRUE;
            }
        }
    }

    compareObject.setIxInfo( this, pIxd);
    compareObject.setCompareNodeIds( bCompareNodeIds);
    compareObject.setCompareDocId( bCompareDocId);
    compareObject.setSearchKey( pSearchKey);

    // Get a btree

    if (RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pbtree)))
    {
        goto Exit;
    }

    if( RC_BAD( rc = pbtree->btOpen( this, pLFile,
                                     (pIxd->uiFlags & IXD_ABS_POS)
                                     ? TRUE
                                     : FALSE,
                                     (pIxd->pFirstData)
                                     ? TRUE
                                     : FALSE, &compareObject)))
    {
        goto Exit;
    }

    // Search the for the key

    if (uiSearchKeyLen)
    {
        f_memcpy( pucFoundKey, pucSearchKey, uiSearchKeyLen);
    }
    uiFoundKeyLen = uiSearchKeyLen;

    if( RC_BAD( rc = pbtree->btLocateEntry(
                         pucFoundKey, XFLM_MAX_KEY_SIZE, &uiFoundKeyLen, uiFlags, NULL,
                         &uiDataLen)))
    {
        if (rc == NE_XFLM_EOF_HIT && uiOriginalFlags & XFLM_EXACT)
        {
            rc = RC_SET( NE_XFLM_NOT_FOUND);
        }
        goto Exit;
    }

    // See if we are in the same key

    if (uiOriginalFlags & XFLM_KEY_EXACT)
    {
        FLMINT	iTmpCmp;

        if (RC_BAD( rc = ixKeyCompare( this, pIxd,
                                       (F_DataVector *)pSearchKey, NULL, NULL,
                                       (uiIdMatchFlags == XFLM_MATCH_DOC_ID) ? TRUE : FALSE,
                                       FALSE, pucFoundKey, uiFoundKeyLen,
                                       pucSearchKey, uiSearchKeyLen, &iTmpCmp)))
        {
            goto Exit;
        }

        if (iTmpCmp != 0)
        {
            rc = (uiOriginalFlags & (XFLM_INCL | XFLM_EXCL))
                 ? RC_SET( NE_XFLM_EOF_HIT)
                 : RC_SET( NE_XFLM_NOT_FOUND);
            goto Exit;
        }
    }

    // Parse the found key into its individual components

    if (pFoundKey)
    {
        pFoundKey->reset();
        if (RC_BAD( rc = pFoundKey->inputKey( pIxd, pucFoundKey, uiFoundKeyLen)))
        {
            goto Exit;
        }

        // See if there is a data part

        if (pIxd->pFirstData)
        {
            FLMUINT		uiDataBufSize;
            FLMBYTE *	pucData;

            // If the data will fit in the search key buffer, just
            // reuse it since we are not going to do anything with
            // it after this.  Otherwise, allocate a new buffer.

            if (uiDataLen <= XFLM_MAX_KEY_SIZE && pucSearchKey)
            {
                uiDataBufSize = XFLM_MAX_KEY_SIZE;
                pucData = pucSearchKey;
            }
            else
            {
                uiDataBufSize = uiDataLen;
                if (RC_BAD( rc = m_tempPool.poolAlloc( uiDataBufSize,
                                                       (void **)&pucData)))
                {
                    goto Exit;
                }
            }

            // Retrieve the data

            if (RC_BAD( rc = pbtree->btGetEntry(
                                 pucFoundKey, XFLM_MAX_KEY_SIZE, uiFoundKeyLen,
                                 pucData, uiDataBufSize, &uiDataLen)))
            {
                goto Exit;
            }

            // Parse the data

            if (RC_BAD( rc = pFoundKey->inputData( pIxd, pucData, uiDataLen)))
            {
                goto Exit;
            }
        }
    }

Exit:

    m_tempPool.poolReset( pvMark);

    if (pbtree)
    {
        gv_XFlmSysData.pBtPool->btpReturnBtree( &pbtree);
    }

    if( bStartedTrans)
    {
        transAbort();
    }

    return( rc);
}