Added support for insert row functionality. Also added SQLStatement object.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@503 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
@@ -311,6 +311,23 @@ public:
|
||||
return( NULL);
|
||||
}
|
||||
|
||||
FINLINE F_COLUMN * findColumn(
|
||||
F_TABLE * pTable,
|
||||
const char * pszColumnName)
|
||||
{
|
||||
NAME_INFO * pNameInfo;
|
||||
|
||||
if (pTable->pColumnNames)
|
||||
{
|
||||
if ((pNameInfo = pTable->pColumnNames->findName( pszColumnName,
|
||||
NULL)) != NULL)
|
||||
{
|
||||
return( getColumn( pTable, pNameInfo->uiItemNum));
|
||||
}
|
||||
}
|
||||
return( NULL);
|
||||
}
|
||||
|
||||
FINLINE F_INDEX * findIndex(
|
||||
const char * pszIndexName)
|
||||
{
|
||||
|
||||
@@ -74,6 +74,47 @@ typedef struct SFLM_CREATE_OPTS
|
||||
|
||||
} SFLM_CREATE_OPTS;
|
||||
|
||||
/// Errors that can occur when parsing an SQL statement.
|
||||
typedef enum
|
||||
{
|
||||
SQL_NO_ERROR = 0,
|
||||
SQL_ERR_EXPECTING_WHITESPACE, ///< 1 = Whitespace required.
|
||||
SQL_ERR_EXPECTING_INTO, ///< 2 = Expecting "INTO" keyword.
|
||||
SQL_ERR_ILLEGAL_TABLE_NAME_CHAR, ///< 3 = Illegal character in table name.
|
||||
SQL_ERR_TABLE_NAME_TOO_LONG, ///< 4 = Table name is too long.
|
||||
SQL_ERR_UNDEFINED_TABLE, ///< 5 = Table name that was specified is not defined.
|
||||
SQL_ERR_TABLE_ALREADY_DEFINED, ///< 6 = Table name is already defined in the database.
|
||||
SQL_ERR_EXPECTING_COMMA, ///< 7 = Expecting comma.
|
||||
SQL_ERR_UNDEFINED_COLUMN, ///< 8 = Column name not defined for table.
|
||||
SQL_ERR_EXPECTING_LPAREN, ///< 9 = Expecting left parenthesis.
|
||||
SQL_ERR_EXPECTING_RPAREN, ///< 10 = Expecting right parenthesis.
|
||||
SQL_ERR_EXPECTING_QUOTE_CHAR, ///< 11 = Expecting a quote character - strings must be quoted.
|
||||
SQL_ERR_MISSING_QUOTE, ///< 12 = Terminating quote missing on a string.
|
||||
SQL_ERR_INVALID_ESCAPED_CHARACTER, ///< 13 = Can only escape quote characters or backslashes in strings.
|
||||
SQL_ERR_CANNOT_UPDATE_SYSTEM_TABLE, ///< 14 = Inserting, modifying, or deleting rows in a system table is not allowed.
|
||||
SQL_ERR_NUMBER_VALUE_EMPTY, ///< 15 = Number value is empty.
|
||||
SQL_ERR_NON_HEX_CHARACTER, ///< 16 = Invalid hex character in binary value.
|
||||
SQL_ERR_NON_NUMERIC_CHARACTER, ///< 17 = Non-numeric character in number value.
|
||||
SQL_ERR_ILLEGAL_HEX_DIGIT, ///< 18 = Illegal hex digit in number value.
|
||||
SQL_ERR_NUMBER_OVERFLOW, ///< 19 = Number exceeds limits for 64 bit numbers.
|
||||
SQL_ERR_BINARY_VALUE_EMPTY, ///< 20 = Binary value is empty.
|
||||
|
||||
// IMPORTANT NOTE: If new codes are added, please update gv_SQLParseErrors in fshell.cpp
|
||||
SQL_NUM_ERRORS
|
||||
} SQLParseError;
|
||||
|
||||
/// Statistics gathered while parsing and executing an SQL statement.
|
||||
typedef struct
|
||||
{
|
||||
FLMUINT uiLines; ///< Total lines read.
|
||||
FLMUINT uiChars; ///< Total characters read.
|
||||
FLMUINT uiErrLineNum; ///< Line number where error occurred.
|
||||
FLMUINT uiErrLineOffset; ///< Offset in line where error occurred.| NOTE: This is a zero-based offset.
|
||||
SQLParseError eErrorType; ///< Parsing error that occurred.
|
||||
FLMUINT uiErrLineFilePos; ///< Absolute offset in the file (or buffer) where the line containing the error occurred.
|
||||
FLMUINT uiErrLineBytes; ///< Number of bytes in the line that contains the error.
|
||||
} SQL_STATS;
|
||||
|
||||
/// Database header.
|
||||
typedef struct SFLM_DB_HDR
|
||||
{
|
||||
@@ -1152,7 +1193,8 @@ typedef struct
|
||||
#define NE_SFLM_RESET_NEEDED 0xE058 ///< 0xE058 = Used during check operations to indicate we need to reset the view.\ NOTE: This is an internal error code.
|
||||
#define NE_SFLM_ILLEGAL_LANGUAGE 0xE059 ///< 0xE059 = Invalid language specified in an index definition.
|
||||
#define NE_SFLM_ROW_DELETED 0xE05A ///< 0xE05A = Row being accessed has been deleted.
|
||||
#define NE_SFLM_ROW_NOT_FOUND 0xE05B ///< 0xE05B - Row being retrieved does not exist.
|
||||
#define NE_SFLM_ROW_NOT_FOUND 0xE05B ///< 0xE05B = Row being retrieved does not exist.
|
||||
#define NE_SFLM_INVALID_SQL 0xE05C ///< 0xE05C = SQL statement is invalid.
|
||||
|
||||
// Dictionary definition errors.
|
||||
|
||||
@@ -1293,6 +1335,19 @@ flminterface IF_BackupStatus : public F_Object
|
||||
FLMUINT64 ui64BytesDone) = 0;
|
||||
};
|
||||
|
||||
/// Structure for sending data in for table columns.
|
||||
typedef struct F_COLUMN_VALUE
|
||||
{
|
||||
FLMUINT uiColumnNum; ///< Column data is for.
|
||||
eDataType eColumnDataType; ///< Column's data type.
|
||||
FLMBYTE* pucColumnValue; ///< Column's value.\ For string data it is a SEN followed by a UTF8 string.\ The SEN
|
||||
///< gives the number of characters (as opposed to bytes) in the string.\ For number
|
||||
///< data there are two pieces.\ The first byte is a 1 or 0, indicating if the
|
||||
///< number is negative (1=negative, 0=positive).\ Following that byte is a
|
||||
///< SEN that contains the absolute value of the number.\ Binary data may be anything.
|
||||
FLMUINT uiValueLen; ///< Length of column's value.
|
||||
} F_COLUMN_VALUE;
|
||||
|
||||
/****************************************************************************
|
||||
Desc:
|
||||
****************************************************************************/
|
||||
@@ -1374,6 +1429,12 @@ flminterface IF_RestoreStatus : public F_Object
|
||||
FLMUINT64 ui64TransId,
|
||||
FLMUINT uiTableNum,
|
||||
FLMUINT64 ui64NextRowId) = 0;
|
||||
|
||||
virtual RCODE reportInsertRow(
|
||||
eRestoreAction * peAction,
|
||||
FLMUINT uiTableNum,
|
||||
F_COLUMN_VALUE * pColumnValues,
|
||||
FLMUINT uiNumColumnValues) = 0;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@@ -485,6 +485,7 @@ FINLINE RCODE FlmStorage2UTF8(
|
||||
#include "filesys.h"
|
||||
#include "flog.h"
|
||||
#include "f_nici.h"
|
||||
#include "sqlstatement.h"
|
||||
|
||||
/****************************************************************************
|
||||
Desc:
|
||||
@@ -1905,6 +1906,11 @@ public:
|
||||
FLMUINT uiTableNum,
|
||||
FLMUINT64 ui64TransId);
|
||||
|
||||
RCODE insertRow(
|
||||
FLMUINT uiTableNum,
|
||||
F_COLUMN_VALUE * pColumnValues,
|
||||
FLMUINT uiNumColumnValues);
|
||||
|
||||
private:
|
||||
|
||||
// This routine assumes that the database mutex is locked
|
||||
@@ -2422,6 +2428,7 @@ friend class F_GlobalCacheMgr;
|
||||
friend class F_QueryResultSet;
|
||||
friend class F_BTreeInfo;
|
||||
friend class SQLQuery;
|
||||
friend class SQLStatement;
|
||||
};
|
||||
|
||||
typedef struct BTREE_INFO
|
||||
|
||||
713
sql/src/rfl.cpp
713
sql/src/rfl.cpp
@@ -46,55 +46,6 @@ FINLINE FLMBOOL F_Rfl::useDataOnlyBlocks(
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Desc:
|
||||
*********************************************************************/
|
||||
class F_RflOStream : public IF_OStream
|
||||
{
|
||||
public:
|
||||
|
||||
F_RflOStream(
|
||||
F_Rfl * pRfl,
|
||||
F_Db * pDb)
|
||||
{
|
||||
m_pRfl = pRfl;
|
||||
m_pRfl->AddRef();
|
||||
m_pDb = pDb;
|
||||
}
|
||||
|
||||
virtual ~F_RflOStream()
|
||||
{
|
||||
if( m_pRfl)
|
||||
{
|
||||
m_pRfl->Release();
|
||||
}
|
||||
}
|
||||
|
||||
RCODE write(
|
||||
const void * pvBuffer,
|
||||
FLMUINT uiBytesToWrite,
|
||||
FLMUINT * puiBytesWritten = NULL);
|
||||
|
||||
RCODE write(
|
||||
IF_PosIStream * pIStream);
|
||||
|
||||
FINLINE RCODE close( void)
|
||||
{
|
||||
if( m_pRfl)
|
||||
{
|
||||
m_pRfl->Release();
|
||||
m_pRfl = NULL;
|
||||
}
|
||||
|
||||
return( NE_SFLM_OK);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
F_Rfl * m_pRfl;
|
||||
F_Db * m_pDb;
|
||||
};
|
||||
|
||||
/********************************************************************
|
||||
Desc:
|
||||
*********************************************************************/
|
||||
@@ -135,6 +86,7 @@ F_Rfl::F_Rfl()
|
||||
m_pIxCompareObject = NULL;
|
||||
m_pCompareObject = NULL;
|
||||
m_uiDisableCount = 0;
|
||||
m_tmpPool.poolInit( 2048);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
@@ -186,6 +138,7 @@ F_Rfl::~F_Rfl()
|
||||
{
|
||||
m_pIxCompareObject->Release();
|
||||
}
|
||||
m_tmpPool.poolFree();
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
@@ -3943,54 +3896,222 @@ Exit:
|
||||
/********************************************************************
|
||||
Desc:
|
||||
*********************************************************************/
|
||||
RCODE F_RflOStream::write(
|
||||
const void * pvBuffer,
|
||||
FLMUINT uiBytesToWrite,
|
||||
FLMUINT * puiBytesWritten)
|
||||
RCODE F_Rfl::logColumnValues(
|
||||
F_Db * pDb,
|
||||
FLMUINT uiTableNum,
|
||||
F_COLUMN_VALUE * pColumnValues,
|
||||
FLMUINT uiNumColumnValues)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
FLMUINT uiPacketLen = RFL_PACKET_OVERHEAD;
|
||||
FLMUINT uiBytesLeftToWrite;
|
||||
FLMUINT uiBytesToWrite;
|
||||
FLMBYTE * pucValue;
|
||||
FLMBYTE * pucOut;
|
||||
FLMBYTE * pucIV;
|
||||
FLMBYTE * pucStart;
|
||||
F_TABLE * pTable = pDb->m_pDict->getTable( uiTableNum);
|
||||
F_COLUMN * pColumn;
|
||||
F_ENCDEF * pTableEncDef = (pTable->lfInfo.uiEncDefNum)
|
||||
? pDb->m_pDict->getEncDef( pTable->lfInfo.uiEncDefNum)
|
||||
: (F_ENCDEF *)NULL;
|
||||
F_ENCDEF * pEncDef;
|
||||
FLMUINT uiIVLen;
|
||||
FLMUINT uiEncLen;
|
||||
FLMUINT uiSenLen1;
|
||||
FLMUINT uiSenLen2;
|
||||
FLMUINT uiSpaceNeeded;
|
||||
FLMUINT uiEncOutputLen;
|
||||
FLMUINT uiBytesAvail;
|
||||
FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer;
|
||||
|
||||
flmAssert( m_pRfl->isLoggingEnabled());
|
||||
flmAssert( isLoggingEnabled());
|
||||
|
||||
if( !m_pRfl->haveBuffSpace( RFL_PACKET_OVERHEAD))
|
||||
if( !haveBuffSpace( RFL_PACKET_OVERHEAD))
|
||||
{
|
||||
if( RC_BAD( rc = m_pRfl->flush( m_pDb, m_pRfl->m_pCurrentBuf)))
|
||||
if( RC_BAD( rc = flush( pDb, m_pCurrentBuf)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
while( uiBytesToWrite)
|
||||
// Go through each column's data
|
||||
|
||||
while (uiNumColumnValues)
|
||||
{
|
||||
if( RC_BAD( rc = m_pRfl->makeRoom( m_pDb, uiBytesToWrite,
|
||||
&uiPacketLen, RFL_DATA_PACKET, &uiBytesAvail, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
f_memcpy( m_pRfl->getPacketPtr() + uiPacketLen, pucBuffer, uiBytesAvail);
|
||||
|
||||
pucBuffer += uiBytesAvail;
|
||||
uiBytesToWrite -= uiBytesAvail;
|
||||
uiPacketLen += uiBytesAvail;
|
||||
|
||||
if( RC_BAD( rc = m_pRfl->finishPacket( m_pDb, RFL_DATA_PACKET,
|
||||
uiPacketLen - RFL_PACKET_OVERHEAD, FALSE)))
|
||||
pColumn = pDb->m_pDict->getColumn( pTable, pColumnValues->uiColumnNum);
|
||||
|
||||
if( RC_BAD( rc = makeRoom( pDb, FLM_MAX_SEN_LEN * 2 + 1,
|
||||
&uiPacketLen, RFL_COLUMN_DATA_PACKET, NULL, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
uiPacketLen = RFL_PACKET_OVERHEAD;
|
||||
}
|
||||
pucOut = pucStart = getPacketPtr() + uiPacketLen;
|
||||
|
||||
if( puiBytesWritten)
|
||||
{
|
||||
*puiBytesWritten = (FLMUINT)(pucBuffer - ((FLMBYTE *)pvBuffer));
|
||||
// Output the column number.
|
||||
|
||||
f_encodeSEN( pColumnValues->uiColumnNum, &pucOut);
|
||||
|
||||
// Output the data type.
|
||||
|
||||
*pucOut++ = (FLMBYTE)pColumnValues->eColumnDataType;
|
||||
|
||||
// Output the value length
|
||||
|
||||
f_encodeSEN( pColumnValues->uiValueLen, &pucOut);
|
||||
|
||||
uiPacketLen += (FLMUINT)(pucOut - pucStart);
|
||||
|
||||
uiBytesLeftToWrite = pColumnValues->uiValueLen;
|
||||
pucValue = pColumnValues->pucColumnValue;
|
||||
while (uiBytesLeftToWrite)
|
||||
{
|
||||
|
||||
// If the column or table are encrypted, we need to make enough room
|
||||
// to encrypt the data.
|
||||
|
||||
pEncDef = (pColumn->uiEncDefNum)
|
||||
? pDb->m_pDict->getEncDef( pColumn->uiEncDefNum)
|
||||
: pTableEncDef;
|
||||
|
||||
if (!pEncDef)
|
||||
{
|
||||
if (RC_BAD( rc = makeRoom( pDb, uiBytesLeftToWrite,
|
||||
&uiPacketLen, RFL_COLUMN_DATA_PACKET, &uiBytesToWrite, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
f_memcpy( getPacketPtr() + uiPacketLen, pucValue, uiBytesToWrite);
|
||||
|
||||
pucValue += uiBytesToWrite;
|
||||
uiBytesLeftToWrite -= uiBytesToWrite;
|
||||
uiPacketLen += uiBytesToWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
uiIVLen = pEncDef->pCcs->getIVLen();
|
||||
flmAssert( uiIVLen == 8 || uiIVLen == 16);
|
||||
uiBytesToWrite = uiBytesLeftToWrite;
|
||||
uiEncLen = getEncLen( uiBytesToWrite);
|
||||
uiSenLen1 = f_getSENByteCount( uiEncLen);
|
||||
uiSenLen2 = f_getSENByteCount( uiBytesToWrite);
|
||||
uiSpaceNeeded = uiSenLen1 + uiSenLen2 + uiIVLen + uiEncLen;
|
||||
if (RC_BAD( rc = makeRoom( pDb, uiSpaceNeeded,
|
||||
&uiPacketLen, RFL_COLUMN_DATA_PACKET, &uiBytesAvail, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If we can't hold the entire encrypted chunk, we must
|
||||
// recalculate down.
|
||||
|
||||
if (uiBytesAvail < uiSpaceNeeded)
|
||||
{
|
||||
|
||||
// If we cannot hold the encrypted length (as a SEN), the
|
||||
// IV, and a minimal encrypted chunk, we need to flush
|
||||
// out the current packet.
|
||||
|
||||
if (uiBytesAvail < uiSenLen1 + uiSenLen2 + uiIVLen + ENCRYPT_MIN_CHUNK_SIZE)
|
||||
{
|
||||
goto Finish_Packet;
|
||||
}
|
||||
|
||||
// Round down to fit whatever data will end right on an
|
||||
// encryption boundary.
|
||||
|
||||
uiBytesToWrite = uiBytesAvail - uiSenLen1 - uiSenLen2 - uiIVLen;
|
||||
uiBytesToWrite -= extraEncBytes( uiBytesToWrite);
|
||||
uiEncLen = getEncLen( uiBytesToWrite);
|
||||
flmAssert( uiEncLen == uiBytesToWrite);
|
||||
|
||||
uiSenLen1 = f_getSENByteCount( uiEncLen);
|
||||
uiSenLen2 = f_getSENByteCount( uiBytesToWrite);
|
||||
uiSpaceNeeded = uiSenLen1 + uiSenLen2 + uiIVLen + uiEncLen;
|
||||
if (RC_BAD( rc = makeRoom( pDb, uiSpaceNeeded,
|
||||
&uiPacketLen, RFL_COLUMN_DATA_PACKET, &uiBytesAvail, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// We should be guaranteed enough room to write everything we
|
||||
// asked for at this point.
|
||||
|
||||
flmAssert( uiBytesAvail >= uiSpaceNeeded);
|
||||
}
|
||||
|
||||
// First output the encrypted length, then the IV, and finally
|
||||
// the data. Then encrypt the data in place.
|
||||
|
||||
pucOut = getPacketPtr() + uiPacketLen;
|
||||
|
||||
// Output the encrypted length
|
||||
|
||||
f_encodeSEN( uiEncLen, &pucOut);
|
||||
|
||||
// Output the actual data length
|
||||
|
||||
f_encodeSEN( uiBytesToWrite, &pucOut);
|
||||
|
||||
// Output the IV
|
||||
|
||||
pucIV = pucOut;
|
||||
if( RC_BAD( rc = pEncDef->pCcs->generateIV( uiIVLen, pucIV)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
pucOut += uiIVLen;
|
||||
|
||||
// Output the unencrypted data and encrypt it in place.
|
||||
|
||||
f_memcpy( pucOut, pucValue, uiBytesToWrite);
|
||||
if (RC_BAD( rc = pDb->encryptData( pEncDef->uiEncDefNum, pucIV,
|
||||
pucOut, uiEncLen, uiBytesToWrite, &uiEncOutputLen)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
flmAssert( uiEncOutputLen == uiEncLen);
|
||||
|
||||
pucValue += uiBytesToWrite;
|
||||
uiBytesLeftToWrite -= uiBytesToWrite;
|
||||
uiPacketLen += (uiSenLen1 + uiSenLen2 + uiIVLen + uiEncLen);
|
||||
}
|
||||
|
||||
Finish_Packet:
|
||||
|
||||
if( RC_BAD( rc = finishPacket( pDb, RFL_COLUMN_DATA_PACKET,
|
||||
uiPacketLen - RFL_PACKET_OVERHEAD, FALSE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
uiPacketLen = RFL_PACKET_OVERHEAD;
|
||||
}
|
||||
pColumnValues++;
|
||||
uiNumColumnValues--;
|
||||
}
|
||||
|
||||
// Add a column number of zero to terminate the columns.
|
||||
|
||||
if (RC_BAD( rc = makeRoom( pDb, 1, &uiPacketLen,
|
||||
RFL_COLUMN_DATA_PACKET, NULL, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pucOut = getPacketPtr() + uiPacketLen;
|
||||
*pucOut++ = 0;
|
||||
uiPacketLen++;
|
||||
|
||||
// Finish the packet.
|
||||
|
||||
if (RC_BAD( rc = finishPacket( pDb, RFL_COLUMN_DATA_PACKET,
|
||||
uiPacketLen - RFL_PACKET_OVERHEAD, FALSE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
@@ -3999,52 +4120,407 @@ Exit:
|
||||
/********************************************************************
|
||||
Desc:
|
||||
*********************************************************************/
|
||||
RCODE F_RflOStream::write(
|
||||
IF_PosIStream * pIStream)
|
||||
RCODE F_Rfl::logInsertRow(
|
||||
F_Db * pDb,
|
||||
FLMUINT uiTableNum,
|
||||
F_COLUMN_VALUE * pColumnValues,
|
||||
FLMUINT uiNumColumnValues)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
FLMUINT uiPacketLen = RFL_PACKET_OVERHEAD;
|
||||
FLMUINT uiBytesToWrite = (FLMUINT)pIStream->remainingSize();
|
||||
FLMUINT uiBytesAvail;
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
FLMUINT uiPacketBodyLen;
|
||||
FLMBYTE * pucPacketBody;
|
||||
FLMBYTE * pucPacketStart;
|
||||
|
||||
flmAssert( pDb->m_uiFlags & FDB_HAS_FILE_LOCK);
|
||||
|
||||
// Do nothing if logging is disabled.
|
||||
|
||||
flmAssert( m_pRfl->isLoggingEnabled());
|
||||
|
||||
if( !m_pRfl->haveBuffSpace( RFL_PACKET_OVERHEAD))
|
||||
if( !isLoggingEnabled())
|
||||
{
|
||||
if( RC_BAD( rc = m_pRfl->flush( m_pDb, m_pRfl->m_pCurrentBuf)))
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Better be in the middle of a transaction.
|
||||
|
||||
flmAssert( m_ui64CurrTransID);
|
||||
|
||||
// Increment the operation count
|
||||
|
||||
m_uiOperCount++;
|
||||
|
||||
// Make sure we have space in the RFL buffer for a complete packet. NOTE:
|
||||
// this is calculating the maximum packet body length that would be needed.
|
||||
|
||||
if( !haveBuffSpace( FLM_MAX_SEN_LEN * 2 + RFL_PACKET_OVERHEAD))
|
||||
{
|
||||
if( RC_BAD( rc = flush( pDb, m_pCurrentBuf)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Get a pointer to where we will be laying down the packet body.
|
||||
|
||||
pucPacketBody = pucPacketStart = getPacketBodyPtr();
|
||||
|
||||
// Output the table number
|
||||
|
||||
f_encodeSEN( uiTableNum, &pucPacketBody);
|
||||
|
||||
// Output the number of column values
|
||||
|
||||
f_encodeSEN( uiNumColumnValues, &pucPacketBody);
|
||||
|
||||
// Finish the packet - calculate the actual packet body length.
|
||||
|
||||
uiPacketBodyLen = (FLMUINT)(pucPacketBody - pucPacketStart);
|
||||
flmAssert( uiPacketBodyLen <= FLM_MAX_SEN_LEN * 2);
|
||||
|
||||
if (RC_BAD( rc = finishPacket( pDb, RFL_INSERT_ROW_PACKET,
|
||||
uiPacketBodyLen, FALSE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Now output the column data
|
||||
|
||||
if (RC_BAD( rc = logColumnValues( pDb, uiTableNum,
|
||||
pColumnValues, uiNumColumnValues)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Desc:
|
||||
*********************************************************************/
|
||||
RCODE F_Rfl::recovInsertRow(
|
||||
F_Db * pDb,
|
||||
const FLMBYTE * pucPacketBody,
|
||||
FLMUINT uiPacketBodyLen,
|
||||
eRestoreAction * peAction)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
FLMUINT uiTableNum;
|
||||
FLMUINT uiNumColumnValues;
|
||||
FLMUINT uiPacketType;
|
||||
F_COLUMN_VALUE * pColValues;
|
||||
F_COLUMN_VALUE * pColumnValue;
|
||||
const FLMBYTE * pucEnd = pucPacketBody + uiPacketBodyLen;
|
||||
FLMUINT uiIVLen;
|
||||
FLMBOOL bHitEnd;
|
||||
FLMUINT uiColumnNum;
|
||||
F_TABLE * pTable;
|
||||
F_COLUMN * pColumn;
|
||||
F_ENCDEF * pTableEncDef;
|
||||
F_ENCDEF * pEncDef;
|
||||
FLMBYTE * pucValue;
|
||||
FLMUINT uiBytesLeftToRead;
|
||||
FLMUINT uiBytesToRead;
|
||||
FLMUINT uiEncLen;
|
||||
FLMBYTE ucIV [16];
|
||||
|
||||
// Get the table number from the packet
|
||||
|
||||
if (RC_BAD( rc = f_decodeSEN( &pucPacketBody, pucEnd, &uiTableNum)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if ((pTable = pDb->m_pDict->getTable( uiTableNum)) == NULL ||
|
||||
pTable->bSystemTable)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_BAD_RFL_PACKET);
|
||||
goto Exit;
|
||||
}
|
||||
pTableEncDef = (pTable->lfInfo.uiEncDefNum)
|
||||
? pDb->m_pDict->getEncDef( pTable->lfInfo.uiEncDefNum)
|
||||
: (F_ENCDEF *)NULL;
|
||||
|
||||
// Get the number of column values from the packet.
|
||||
|
||||
if (RC_BAD( rc = f_decodeSEN( &pucPacketBody, pucEnd, &uiNumColumnValues)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Get the column values.
|
||||
|
||||
if (uiNumColumnValues)
|
||||
{
|
||||
|
||||
// Allocate space for the values.
|
||||
|
||||
m_tmpPool.poolReset( NULL);
|
||||
if (RC_BAD( rc = m_tmpPool.poolAlloc(
|
||||
sizeof( F_COLUMN_VALUE) * uiNumColumnValues,
|
||||
(void **)&pColValues)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Go into a loop processing packets until we have retrieved all of
|
||||
// the columns. At that point, we had better be at the end
|
||||
// of the column data.
|
||||
|
||||
pColumnValue = pColValues;
|
||||
pucPacketBody = pucEnd = NULL;
|
||||
for (;;)
|
||||
{
|
||||
|
||||
// If we have used everything in our current packet, get another.
|
||||
|
||||
if (pucPacketBody == pucEnd)
|
||||
{
|
||||
if( RC_BAD( rc = getPacket(
|
||||
pDb, FALSE, &uiPacketType, &pucPacketBody, &uiPacketBodyLen,
|
||||
&bHitEnd)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Should not hit the end of the RFL here!
|
||||
|
||||
if (bHitEnd)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_RFL_INCOMPLETE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (uiPacketType != RFL_COLUMN_DATA_PACKET)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_BAD_RFL_PACKET);
|
||||
goto Exit;
|
||||
}
|
||||
pucEnd = pucPacketBody + uiPacketBodyLen;
|
||||
}
|
||||
|
||||
// Get the column number.
|
||||
|
||||
if (RC_BAD( rc = f_decodeSEN( &pucPacketBody, pucEnd, &uiColumnNum)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// A zero column number means we are at the end
|
||||
|
||||
if (!uiColumnNum)
|
||||
{
|
||||
|
||||
// Shouldn't have hit zero if we still have column values to
|
||||
// process.
|
||||
|
||||
if (uiNumColumnValues)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_BAD_RFL_PACKET);
|
||||
goto Exit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((pColumn = pDb->m_pDict->getColumn( pTable, uiColumnNum)) == NULL)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_BAD_RFL_PACKET);
|
||||
goto Exit;
|
||||
}
|
||||
pColumnValue->uiColumnNum = uiColumnNum;
|
||||
|
||||
// Get the data type
|
||||
|
||||
if (pucPacketBody >= pucEnd)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_BAD_RFL_PACKET);
|
||||
goto Exit;
|
||||
}
|
||||
pColumnValue->eColumnDataType = (eDataType)(*pucPacketBody);
|
||||
switch (pColumnValue->eColumnDataType)
|
||||
{
|
||||
case SFLM_STRING_TYPE:
|
||||
case SFLM_NUMBER_TYPE:
|
||||
case SFLM_BINARY_TYPE:
|
||||
break;
|
||||
default:
|
||||
rc = RC_SET( NE_SFLM_BAD_RFL_PACKET);
|
||||
goto Exit;
|
||||
}
|
||||
pucPacketBody++;
|
||||
|
||||
// Get the value length.
|
||||
|
||||
if (RC_BAD( rc = f_decodeSEN( &pucPacketBody, pucEnd,
|
||||
&uiBytesLeftToRead)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Get the value, if there is one.
|
||||
|
||||
if ((pColumnValue->uiValueLen = uiBytesLeftToRead) != 0)
|
||||
{
|
||||
pEncDef = (pColumn->uiEncDefNum)
|
||||
? pDb->m_pDict->getEncDef( pColumn->uiEncDefNum)
|
||||
: pTableEncDef;
|
||||
|
||||
// If data is encrypted, allocate enough so that we can
|
||||
// decrypt in place - rounding up to nearest encryption boundary
|
||||
// should ensure that.
|
||||
|
||||
if (!pEncDef)
|
||||
{
|
||||
if (RC_BAD( rc = m_tmpPool.poolAlloc( uiBytesLeftToRead,
|
||||
(void **)&pucValue)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RC_BAD( rc = m_tmpPool.poolAlloc( getEncLen( uiBytesLeftToRead),
|
||||
(void **)&pucValue)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
pColumnValue->pucColumnValue = pucValue;
|
||||
|
||||
// Now get the value.
|
||||
|
||||
while (uiBytesLeftToRead)
|
||||
{
|
||||
|
||||
// If we have used up our current packet, get another.
|
||||
|
||||
if (pucPacketBody == pucEnd)
|
||||
{
|
||||
if( RC_BAD( rc = getPacket(
|
||||
pDb, FALSE, &uiPacketType, &pucPacketBody, &uiPacketBodyLen,
|
||||
&bHitEnd)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Should not hit the end of the RFL here!
|
||||
|
||||
if (bHitEnd)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_RFL_INCOMPLETE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (uiPacketType != RFL_COLUMN_DATA_PACKET)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_BAD_RFL_PACKET);
|
||||
goto Exit;
|
||||
}
|
||||
pucEnd = pucPacketBody + uiPacketBodyLen;
|
||||
}
|
||||
|
||||
// Getting data is simple if it is not encrypted.
|
||||
|
||||
if (!pEncDef)
|
||||
{
|
||||
uiBytesToRead = (FLMUINT)(pucEnd - pucPacketBody);
|
||||
if (uiBytesToRead > uiBytesLeftToRead)
|
||||
{
|
||||
uiBytesToRead = uiBytesLeftToRead;
|
||||
}
|
||||
f_memcpy( pucValue, pucPacketBody, uiBytesToRead);
|
||||
pucPacketBody += uiBytesToRead;
|
||||
pucValue += uiBytesToRead;
|
||||
uiBytesLeftToRead -= uiBytesToRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Encrypted data should have the encrypted length, the
|
||||
// length of data encrypted, an IV, and the encrypted
|
||||
// data - all in the same packet.
|
||||
|
||||
if (RC_BAD( rc = f_decodeSEN( &pucPacketBody, pucEnd,
|
||||
&uiEncLen)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (RC_BAD( rc = f_decodeSEN( &pucPacketBody, pucEnd,
|
||||
&uiBytesToRead)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (uiBytesToRead > uiEncLen || uiBytesToRead > uiBytesLeftToRead)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_BAD_RFL_PACKET);
|
||||
goto Exit;
|
||||
}
|
||||
uiIVLen = pEncDef->pCcs->getIVLen();
|
||||
flmAssert( uiIVLen == 8 || uiIVLen == 16);
|
||||
|
||||
// Make sure packet has the IV and the encrypted data.
|
||||
|
||||
if (pucPacketBody + uiIVLen + uiEncLen > pucEnd)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_BAD_RFL_PACKET);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Get the IV from the packet.
|
||||
|
||||
f_memcpy( ucIV, pucPacketBody, uiIVLen);
|
||||
pucPacketBody += uiIVLen;
|
||||
|
||||
// Get the encrypted data into our buffer.
|
||||
|
||||
f_memcpy( pucValue, pucPacketBody, uiEncLen);
|
||||
|
||||
// Decrypt the data in place.
|
||||
|
||||
if (RC_BAD( rc = pDb->decryptData( pEncDef->uiEncDefNum, ucIV,
|
||||
pucValue, uiEncLen, pucValue, uiEncLen)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Increment our value buffer only past the decrypted data.
|
||||
// Increment the packet body pointer past the encrypted data.
|
||||
|
||||
pucValue += uiBytesToRead;
|
||||
uiBytesLeftToRead -= uiBytesToRead;
|
||||
pucPacketBody += uiEncLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uiNumColumnValues--;
|
||||
pColumnValue++;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pRestoreStatus)
|
||||
{
|
||||
if( RC_BAD( rc = m_pRestoreStatus->reportInsertRow(
|
||||
peAction, uiTableNum, pColValues, uiNumColumnValues)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if( *peAction == SFLM_RESTORE_ACTION_STOP)
|
||||
{
|
||||
m_ui64CurrTransID = 0;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
while( uiBytesToWrite)
|
||||
if( RC_BAD( rc = pDb->insertRow( uiTableNum, pColValues, uiNumColumnValues)))
|
||||
{
|
||||
if( RC_BAD( rc = m_pRfl->makeRoom( m_pDb, uiBytesToWrite,
|
||||
&uiPacketLen, RFL_DATA_PACKET, &uiBytesAvail, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if( RC_BAD( rc = pIStream->read( m_pRfl->getPacketPtr()+ uiPacketLen,
|
||||
uiBytesAvail)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
uiBytesToWrite -= uiBytesAvail;
|
||||
uiPacketLen += uiBytesAvail;
|
||||
|
||||
if( RC_BAD( rc = m_pRfl->finishPacket( m_pDb, RFL_DATA_PACKET,
|
||||
uiPacketLen - RFL_PACKET_OVERHEAD, FALSE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
uiPacketLen = RFL_PACKET_OVERHEAD;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
m_tmpPool.poolReset( NULL);
|
||||
|
||||
m_ui64CurrTransID = 0;
|
||||
return( rc);
|
||||
}
|
||||
|
||||
@@ -5369,6 +5845,23 @@ Finish_Transaction:
|
||||
goto Finish_Transaction;
|
||||
}
|
||||
|
||||
case RFL_INSERT_ROW_PACKET:
|
||||
{
|
||||
if( RC_BAD( rc = recovInsertRow( pDb,
|
||||
pucPacketBody, uiPacketBodyLen, &eAction)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if( eAction == SFLM_RESTORE_ACTION_STOP)
|
||||
{
|
||||
bLastTransEndedAtFileEOF = FALSE;
|
||||
goto Finish_Recovery;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// Should not be getting other packet types at this
|
||||
|
||||
@@ -44,6 +44,8 @@ class IXKeyCompare;
|
||||
#define RFL_DATA_PACKET 11
|
||||
#define RFL_ROLL_OVER_DB_KEY_PACKET 12
|
||||
#define RFL_ENC_DEF_KEY_PACKET 13
|
||||
#define RFL_INSERT_ROW_PACKET 14
|
||||
#define RFL_COLUMN_DATA_PACKET 15
|
||||
|
||||
#define RFL_PACKET_TYPE_MASK 0x7F
|
||||
|
||||
@@ -199,6 +201,24 @@ public:
|
||||
RCODE logRollOverDbKey(
|
||||
F_Db * pDb);
|
||||
|
||||
RCODE logColumnValues(
|
||||
F_Db * pDb,
|
||||
FLMUINT uiTableNum,
|
||||
F_COLUMN_VALUE * pColumnValues,
|
||||
FLMUINT uiNumColumnValues);
|
||||
|
||||
RCODE logInsertRow(
|
||||
F_Db * pDb,
|
||||
FLMUINT uiTableNum,
|
||||
F_COLUMN_VALUE * pColumnValues,
|
||||
FLMUINT uiNumColumnValues);
|
||||
|
||||
RCODE recovInsertRow(
|
||||
F_Db * pDb,
|
||||
const FLMBYTE * pucPacketBody,
|
||||
FLMUINT uiPacketBodyLen,
|
||||
eRestoreAction * peAction);
|
||||
|
||||
RCODE recover(
|
||||
F_Db * pDb,
|
||||
IF_RestoreClient * pRestore,
|
||||
@@ -631,6 +651,7 @@ private:
|
||||
IXKeyCompare * m_pIxCompareObject;
|
||||
IF_ResultSetCompare * m_pCompareObject;
|
||||
FLMUINT m_uiDisableCount; // Is logging currently disabled
|
||||
F_Pool m_tmpPool;
|
||||
|
||||
friend class F_RflOStream;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user