You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
887 lines
40 KiB
887 lines
40 KiB
//--------------------------------------------------------------------------
|
|
// Database.h
|
|
//--------------------------------------------------------------------------
|
|
#pragma once
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Depends
|
|
//--------------------------------------------------------------------------
|
|
#include "utility.h"
|
|
#include "query.h"
|
|
#include "listen.h"
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Forward Decls
|
|
//--------------------------------------------------------------------------
|
|
class CDatabaseQuery;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DwordAlign
|
|
//--------------------------------------------------------------------------
|
|
inline DWORD DwordAlign(DWORD cb) {
|
|
DWORD dw = (cb % 4); return(0 == dw ? 0 : (4 - dw));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// String Constants
|
|
//--------------------------------------------------------------------------
|
|
#define CCHMAX_DB_FILEPATH (MAX_PATH + MAX_PATH)
|
|
|
|
//--------------------------------------------------------------------------
|
|
// DESCENDING
|
|
//--------------------------------------------------------------------------
|
|
#define DESCENDING(_nCompare) ((_nCompare < 0) ? 1 : -1)
|
|
typedef DWORD TICKCOUNT;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Version and Signatures
|
|
//--------------------------------------------------------------------------
|
|
#define BTREE_SIGNATURE 0xfe12adcf
|
|
#define BTREE_VERSION 5
|
|
|
|
//--------------------------------------------------------------------------
|
|
// B-Tree Chain Sizes
|
|
//--------------------------------------------------------------------------
|
|
#define BTREE_ORDER 50
|
|
#define BTREE_MIN_CAP 25
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Upper Limit on Various Resources
|
|
//--------------------------------------------------------------------------
|
|
#define CMAX_OPEN_STREAMS 512
|
|
#define CMAX_OPEN_ROWSETS 32
|
|
#define CMAX_RECIPIENTS 15
|
|
#define CMAX_CLIENTS 32
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Block Allocate Page Sizes
|
|
//--------------------------------------------------------------------------
|
|
#define CB_CHAIN_PAGE 15900
|
|
#define CB_STREAM_PAGE 63360
|
|
#define CB_VARIABLE_PAGE 49152
|
|
#define CB_STREAM_BLOCK 512
|
|
#define CC_MAX_BLOCK_TYPES 16
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Variable Length Block Allocation Sizes
|
|
//--------------------------------------------------------------------------
|
|
#define CB_ALIGN_LARGE 1024
|
|
#define CB_FREE_BUCKET 4
|
|
#define CC_FREE_BUCKETS 2048
|
|
#define CB_MIN_FREE_BUCKET 32
|
|
#define CB_MAX_FREE_BUCKET (CB_MIN_FREE_BUCKET + (CB_FREE_BUCKET * CC_FREE_BUCKETS))
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Heap Block Cache
|
|
//--------------------------------------------------------------------------
|
|
#define CB_HEAP_BUCKET 8
|
|
#define CC_HEAP_BUCKETS 1024
|
|
#define CB_MAX_HEAP_BUCKET (CB_HEAP_BUCKET * CC_HEAP_BUCKETS)
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Other Constants
|
|
//--------------------------------------------------------------------------
|
|
#define MEMORY_GUARD_SIGNATURE 0xdeadbeef
|
|
#define DELETE_ON_CLOSE TRUE
|
|
|
|
//--------------------------------------------------------------------------
|
|
// File Mapping Constants
|
|
//--------------------------------------------------------------------------
|
|
#define CB_MAPPED_VIEW 10485760
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Forward Decls
|
|
//--------------------------------------------------------------------------
|
|
class CProgress;
|
|
class CDatabase;
|
|
class CDatabaseStream;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Locking Values
|
|
//--------------------------------------------------------------------------
|
|
#define LOCK_VALUE_NONE 0
|
|
#define LOCK_VALUE_WRITER -1
|
|
|
|
//--------------------------------------------------------------------------
|
|
// STREAMINDEX
|
|
//--------------------------------------------------------------------------
|
|
typedef WORD STREAMINDEX;
|
|
typedef LPWORD LPSTREAMINDEX;
|
|
#define INVALID_STREAMINDEX 0xffff
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ROWSETORDINAL
|
|
//--------------------------------------------------------------------------
|
|
typedef BYTE ROWSETORDINAL;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// FILEADDRESS
|
|
//--------------------------------------------------------------------------
|
|
typedef DWORD FILEADDRESS;
|
|
typedef LPDWORD LPFILEADDRESS;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// NODEINDEX
|
|
//--------------------------------------------------------------------------
|
|
typedef BYTE NODEINDEX;
|
|
typedef BYTE *LPNODEINDEX;
|
|
#define INVALID_NODEINDEX 0xff
|
|
|
|
//--------------------------------------------------------------------------
|
|
// BLOCKTYPE
|
|
//--------------------------------------------------------------------------
|
|
typedef enum tagBLOCKTYPE {
|
|
BLOCK_RECORD,
|
|
BLOCK_STRING,
|
|
BLOCK_RESERVED1,
|
|
BLOCK_TRANSACTION,
|
|
BLOCK_CHAIN,
|
|
BLOCK_STREAM,
|
|
BLOCK_FREE,
|
|
BLOCK_ENDOFPAGE,
|
|
BLOCK_RESERVED2,
|
|
BLOCK_RESERVED3,
|
|
BLOCK_LAST
|
|
} BLOCKTYPE;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CHAINDELETETYPE
|
|
//--------------------------------------------------------------------------
|
|
typedef enum tagCHAINDELETETYPE {
|
|
CHAIN_DELETE_SHARE,
|
|
CHAIN_DELETE_COALESCE
|
|
} CHAINDELETETYPE;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CHAINSHARETYPE
|
|
//--------------------------------------------------------------------------
|
|
typedef enum tagCHAINSHARETYPE {
|
|
CHAIN_SHARE_LEFT,
|
|
CHAIN_SHARE_RIGHT
|
|
} CHAINSHARETYPE;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OPERATIONTYPE - Specifies how _UnlinkRecordFromTable from table works
|
|
//--------------------------------------------------------------------------
|
|
typedef enum tagOPERATIONTYPE {
|
|
OPERATION_DELETE,
|
|
OPERATION_UPDATE,
|
|
OPERATION_INSERT
|
|
} OPERATIONTYPE;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// INVOKETYPE
|
|
//--------------------------------------------------------------------------
|
|
typedef enum tagINVOKETYPE {
|
|
INVOKE_RELEASEMAP = 100,
|
|
INVOKE_CREATEMAP = 101,
|
|
INVOKE_CLOSEFILE = 102,
|
|
INVOKE_OPENFILE = 103,
|
|
INVOKE_OPENMOVEDFILE = 104
|
|
} INVOKETYPE;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// FINDRESULT
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagFINDRESULT {
|
|
FILEADDRESS faChain;
|
|
NODEINDEX iNode;
|
|
BYTE fChanged;
|
|
BYTE fFound;
|
|
INT nCompare;
|
|
} FINDRESULT, *LPFINDRESULT;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ALLOCATEPAGE
|
|
//--------------------------------------------------------------------------
|
|
#pragma pack(4)
|
|
typedef struct tagALLOCATEPAGE {
|
|
FILEADDRESS faPage;
|
|
DWORD cbPage;
|
|
DWORD cbUsed;
|
|
} ALLOCATEPAGE, *LPALLOCATEPAGE;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// TABLEHEADER
|
|
//--------------------------------------------------------------------------
|
|
#pragma pack(4)
|
|
typedef struct tagTABLEHEADER {
|
|
DWORD dwSignature; // 4
|
|
CLSID clsidExtension; // 20
|
|
DWORD dwMinorVersion; // 24
|
|
DWORD dwMajorVersion; // 28
|
|
DWORD cbUserData; // 32
|
|
FILEADDRESS faCatalogOld; // 36
|
|
ALLOCATEPAGE AllocateRecord; // 48
|
|
ALLOCATEPAGE AllocateChain; // 60
|
|
ALLOCATEPAGE AllocateStream; // 72
|
|
FILEADDRESS faFreeStreamBlock; // 76
|
|
FILEADDRESS faFreeChainBlock; // 80
|
|
FILEADDRESS faFreeLargeBlock; // 84
|
|
DWORD cbAllocated; // 88
|
|
DWORD cbFreed; // 92
|
|
DWORD dwNextId; // 96
|
|
DWORD fCorrupt; // 100
|
|
DWORD fCorruptCheck; // 104
|
|
DWORD cActiveThreads; // 108
|
|
FILEADDRESS faTransactHead; // 112
|
|
FILEADDRESS faTransactTail; // 116
|
|
DWORD cTransacts; // 120
|
|
DWORD cBadCloses; // 124
|
|
FILEADDRESS faNextAllocate; // 128
|
|
DWORD cIndexes; // 132
|
|
FILEADDRESS rgfaFilter[CMAX_INDEXES]; // 164
|
|
DWORD rgbReserved5[8]; // 196
|
|
DWORD rgcRecords[CMAX_INDEXES]; // 228
|
|
FILEADDRESS rgfaIndex[CMAX_INDEXES]; // 260
|
|
INDEXORDINAL rgiIndex[CMAX_INDEXES]; // 292
|
|
BYTE rgbReserved4[116]; // 408
|
|
BYTE fReserved; // 409
|
|
DWORD rgbReserved6[8]; // 196
|
|
BYTE rgdwReserved2[192]; // 637
|
|
DWORD rgcbAllocated[CC_MAX_BLOCK_TYPES]; // 701
|
|
FILEADDRESS rgfaFreeBlock[CC_FREE_BUCKETS]; // 8893
|
|
TABLEINDEX rgIndexInfo[CMAX_INDEXES]; // 9293
|
|
WORD wTransactSize; // 9405
|
|
BYTE rgdwReserved3[110];
|
|
} TABLEHEADER, *LPTABLEHEADER;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// BLOCKHEADER
|
|
//--------------------------------------------------------------------------
|
|
#pragma pack(4)
|
|
typedef struct tagBLOCKHEADER {
|
|
FILEADDRESS faBlock;
|
|
DWORD cbSize;
|
|
} BLOCKHEADER, *LPBLOCKHEADER;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// FREEBLOCK
|
|
//--------------------------------------------------------------------------
|
|
#pragma pack(4)
|
|
typedef struct tagFREEBLOCK : public BLOCKHEADER {
|
|
DWORD cbBlock;
|
|
DWORD dwReserved;
|
|
FILEADDRESS faNext;
|
|
} FREEBLOCK, *LPFREEBLOCK;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CHAINNODE
|
|
//--------------------------------------------------------------------------
|
|
#pragma pack(4)
|
|
typedef struct tagCHAINNODE {
|
|
FILEADDRESS faRecord;
|
|
FILEADDRESS faRightChain;
|
|
DWORD cRightNodes;
|
|
} CHAINNODE, *LPCHAINNODE;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CHAINBLOCK - 636
|
|
//--------------------------------------------------------------------------
|
|
#pragma pack(4)
|
|
typedef struct tagCHAINBLOCK : public BLOCKHEADER {
|
|
FILEADDRESS faLeftChain;
|
|
FILEADDRESS faParent;
|
|
BYTE iParent;
|
|
BYTE cNodes;
|
|
WORD wReserved;
|
|
DWORD cLeftNodes;
|
|
CHAINNODE rgNode[BTREE_ORDER + 1];
|
|
} CHAINBLOCK, *LPCHAINBLOCK;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// STREAMBLOCK
|
|
//--------------------------------------------------------------------------
|
|
#pragma pack(4)
|
|
typedef struct tagSTREAMBLOCK : public BLOCKHEADER {
|
|
DWORD cbData;
|
|
FILEADDRESS faNext;
|
|
} STREAMBLOCK, *LPSTREAMBLOCK;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// RECORDBLOCK
|
|
//--------------------------------------------------------------------------
|
|
#pragma pack(4)
|
|
typedef struct tagRECORDBLOCK : public BLOCKHEADER {
|
|
WORD wReserved;
|
|
BYTE cTags;
|
|
BYTE bVersion;
|
|
} RECORDBLOCK, *LPRECORDBLOCK;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// COLUMNTAG
|
|
//--------------------------------------------------------------------------
|
|
#define TAG_DATA_MASK 0xFF800000
|
|
#pragma pack(4)
|
|
typedef struct tagCOLUMNTAG {
|
|
unsigned iColumn : 7;
|
|
unsigned fData : 1;
|
|
unsigned Offset : 24;
|
|
} COLUMNTAG, *LPCOLUMNTAG;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// RECORDMAP
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagRECORDMAP {
|
|
LPCTABLESCHEMA pSchema;
|
|
BYTE cTags;
|
|
LPCOLUMNTAG prgTag;
|
|
DWORD cbTags;
|
|
DWORD cbData;
|
|
LPBYTE pbData;
|
|
} RECORDMAP, *LPRECORDMAP;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// OPENSTREAM
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagOPENSTREAM {
|
|
BYTE fInUse;
|
|
FILEADDRESS faStart;
|
|
FILEADDRESS faMoved;
|
|
DWORD cOpenCount;
|
|
LONG lLock;
|
|
BYTE fDeleteOnClose;
|
|
} OPENSTREAM, *LPOPENSTREAM;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// NOTIFYRECIPIENT
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagNOTIFYRECIPIENT {
|
|
HWND hwndNotify;
|
|
DWORD dwThreadId;
|
|
DWORD_PTR dwCookie;
|
|
BYTE fSuspended;
|
|
BYTE fRelease;
|
|
BYTE fOrdinalsOnly;
|
|
DWORD_PTR pNotify;
|
|
INDEXORDINAL iIndex;
|
|
} NOTIFYRECIPIENT, *LPNOTIFYRECIPIENT;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLIENTENTRY
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagCLIENTENTRY {
|
|
HWND hwndListen;
|
|
DWORD dwProcessId;
|
|
DWORD dwThreadId;
|
|
DWORD_PTR pDB;
|
|
DWORD cRecipients;
|
|
NOTIFYRECIPIENT rgRecipient[CMAX_RECIPIENTS];
|
|
} CLIENTENTRY, *LPCLIENTENTRY;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// TRANSACTIONBLOCK
|
|
//--------------------------------------------------------------------------
|
|
#pragma pack(4)
|
|
typedef struct tagTRANSACTIONBLOCK : public BLOCKHEADER {
|
|
TRANSACTIONTYPE tyTransaction;
|
|
WORD cRefs;
|
|
INDEXORDINAL iIndex;
|
|
ORDINALLIST Ordinals;
|
|
FILEADDRESS faRecord1;
|
|
FILEADDRESS faRecord2;
|
|
FILEADDRESS faNext;
|
|
FILEADDRESS faPrevious;
|
|
FILEADDRESS faNextInBatch;
|
|
} TRANSACTIONBLOCK, *LPTRANSACTIONBLOCK;
|
|
#pragma pack()
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ROWSETINFO
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagROWSETINFO {
|
|
ROWSETORDINAL iRowset;
|
|
INDEXORDINAL iIndex;
|
|
ROWORDINAL iRow;
|
|
} ROWSETINFO, *LPROWSETINFO;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// ROWSETTABLE
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagROWSETTABLE {
|
|
BYTE fInitialized;
|
|
BYTE cFree;
|
|
BYTE cUsed;
|
|
ROWSETORDINAL rgiFree[CMAX_OPEN_ROWSETS];
|
|
ROWSETORDINAL rgiUsed[CMAX_OPEN_ROWSETS];
|
|
ROWSETINFO rgRowset[CMAX_OPEN_ROWSETS];
|
|
} ROWSETTABLE, *LPROWSETTABLE;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// SHAREDDATABASE
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagSHAREDDATABASE {
|
|
WCHAR szFile[CCHMAX_DB_FILEPATH];
|
|
LONG cWaitingForLock;
|
|
BYTE fCompacting;
|
|
DWORD dwVersion;
|
|
DWORD dwQueryVersion;
|
|
DWORD cNotifyLock;
|
|
FILEADDRESS faTransactLockHead;
|
|
FILEADDRESS faTransactLockTail;
|
|
OPENSTREAM rgStream[CMAX_OPEN_STREAMS];
|
|
DWORD cClients;
|
|
DWORD cNotifyOrdinalsOnly;
|
|
DWORD cNotifyWithData;
|
|
DWORD cNotify;
|
|
DWORD rgcIndexNotify[CMAX_INDEXES];
|
|
CLIENTENTRY rgClient[CMAX_CLIENTS];
|
|
ROWSETTABLE Rowsets;
|
|
IF_DEBUG(BYTE fRepairing;)
|
|
} SHAREDDATABASE, *LPSHAREDDATABASE;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// INVOKEPACKAGE
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagINVOKEPACKAGE {
|
|
INVOKETYPE tyInvoke;
|
|
DWORD_PTR pDB;
|
|
} INVOKEPACKAGE, *LPINVOKEPACKAGE;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// MARKBLOCK
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagMARKBLOCK {
|
|
DWORD cbBlock;
|
|
} MARKBLOCK, *LPMARKBLOCK;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// FILEVIEW
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagFILEVIEW *LPFILEVIEW;
|
|
typedef struct tagFILEVIEW {
|
|
FILEADDRESS faView;
|
|
LPBYTE pbView;
|
|
DWORD cbView;
|
|
LPFILEVIEW pNext;
|
|
} FILEVIEW, *LPFILEVIEW;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// STORAGEINFO
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagSTORAGEINFO {
|
|
LPWSTR pszMap;
|
|
HANDLE hFile;
|
|
HANDLE hMap;
|
|
HANDLE hShare;
|
|
DWORD cbFile;
|
|
#ifdef BACKGROUND_MONITOR
|
|
TICKCOUNT tcMonitor;
|
|
#endif
|
|
DWORD cbMappedViews;
|
|
DWORD cbMappedSpecial;
|
|
DWORD cAllocated;
|
|
DWORD cSpecial;
|
|
LPFILEVIEW prgView;
|
|
LPFILEVIEW pSpecial;
|
|
} STORAGEINFO, *LPSTORAGEINFO;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// MEMORYTAG
|
|
//--------------------------------------------------------------------------
|
|
typedef struct tagMEMORYTAG {
|
|
DWORD dwSignature;
|
|
DWORD cbSize;
|
|
LPVOID pNext;
|
|
} MEMORYTAG, *LPMEMORYTAG;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CORRUPTREASON
|
|
//--------------------------------------------------------------------------
|
|
typedef enum tagCORRUPTREASON {
|
|
REASON_BLOCKSTARTOUTOFRANGE = 10000,
|
|
REASON_UMATCHINGBLOCKADDRESS = 10002,
|
|
REASON_BLOCKSIZEOUTOFRANGE = 10003,
|
|
REASON_INVALIDFIRSTRECORD = 10035,
|
|
REASON_INVALIDLASTRECORD = 10036,
|
|
REASON_INVALIDRECORDMAP = 10037
|
|
} CORRUPTREASON;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CDatabase
|
|
//--------------------------------------------------------------------------
|
|
class CDatabase : public IDatabase
|
|
{
|
|
public:
|
|
//----------------------------------------------------------------------
|
|
// Construction - Destruction
|
|
//----------------------------------------------------------------------
|
|
CDatabase(void);
|
|
~CDatabase(void);
|
|
|
|
//----------------------------------------------------------------------
|
|
// IUnknown Members
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv);
|
|
STDMETHODIMP_(ULONG) AddRef(void);
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
//----------------------------------------------------------------------
|
|
// IDatabase Members
|
|
//----------------------------------------------------------------------
|
|
HRESULT Open(LPCWSTR pszFile, OPENDATABASEFLAGS dwFlags, LPCTABLESCHEMA pSchema, IDatabaseExtension *pExtension);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Locking Methods
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP Lock(LPHLOCK phLock);
|
|
STDMETHODIMP Unlock(LPHLOCK phLock);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Data Manipulation Methods
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP InsertRecord(LPVOID pBinding);
|
|
STDMETHODIMP UpdateRecord(LPVOID pBinding);
|
|
STDMETHODIMP DeleteRecord(LPVOID pBinding);
|
|
STDMETHODIMP FindRecord(INDEXORDINAL iIndex, DWORD cColumns, LPVOID pBinding, LPROWORDINAL piRow);
|
|
STDMETHODIMP GetRowOrdinal(INDEXORDINAL iIndex, LPVOID pBinding, LPROWORDINAL piRow);
|
|
STDMETHODIMP FreeRecord(LPVOID pBinding);
|
|
STDMETHODIMP GetUserData(LPVOID pvUserData, ULONG cbUserData);
|
|
STDMETHODIMP SetUserData(LPVOID pvUserData, ULONG cbUserData);
|
|
STDMETHODIMP GetRecordCount(INDEXORDINAL iIndex, LPDWORD pcRecords);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Indexing Methods
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP GetIndexInfo(INDEXORDINAL iIndex, LPSTR *ppszFilter, LPTABLEINDEX pIndex);
|
|
STDMETHODIMP ModifyIndex(INDEXORDINAL iIndex, LPCSTR pszFilter, LPCTABLEINDEX pIndex);
|
|
STDMETHODIMP DeleteIndex(INDEXORDINAL iIndex);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Rowset Methods
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CreateRowset(INDEXORDINAL iIndex, CREATEROWSETFLAGS dwFlags, LPHROWSET phRowset);
|
|
STDMETHODIMP SeekRowset(HROWSET hRowset, SEEKROWSETTYPE tySeek, LONG cRows, LPROWORDINAL piRowNew);
|
|
STDMETHODIMP QueryRowset(HROWSET hRowset, LONG cWanted, LPVOID *prgpBinding, LPDWORD pcObtained);
|
|
STDMETHODIMP CloseRowset(LPHROWSET phRowset);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Streaming Methods
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP CreateStream(LPFILEADDRESS pfaStart);
|
|
STDMETHODIMP DeleteStream(FILEADDRESS faStart);
|
|
STDMETHODIMP CopyStream(IDatabase *pDst, FILEADDRESS faStream, LPFILEADDRESS pfaNew);
|
|
STDMETHODIMP OpenStream(ACCESSTYPE tyAccess, FILEADDRESS faStart, IStream **ppStream);
|
|
STDMETHODIMP ChangeStreamLock(IStream *pStream, ACCESSTYPE tyAccessNew);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Notification Methods
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP RegisterNotify(INDEXORDINAL iIndex, REGISTERNOTIFYFLAGS dwFlags, DWORD_PTR dwCookie, IDatabaseNotify *pNotify);
|
|
STDMETHODIMP DispatchNotify(IDatabaseNotify *pNotify);
|
|
STDMETHODIMP SuspendNotify(IDatabaseNotify *pNotify);
|
|
STDMETHODIMP ResumeNotify(IDatabaseNotify *pNotify);
|
|
STDMETHODIMP UnregisterNotify(IDatabaseNotify *pNotify);
|
|
STDMETHODIMP LockNotify(LOCKNOTIFYFLAGS dwFlags, LPHLOCK phLock);
|
|
STDMETHODIMP UnlockNotify(LPHLOCK phLock);
|
|
STDMETHODIMP GetTransaction(LPHTRANSACTION phTransaction, LPTRANSACTIONTYPE ptyTransaction, LPVOID pRecord1, LPVOID pRecord2, LPINDEXORDINAL piIndex, LPORDINALLIST pOrdinals);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Maintenence Methods
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP MoveFile(LPCWSTR pszFilePath);
|
|
STDMETHODIMP SetSize(DWORD cbSize);
|
|
STDMETHODIMP GetFile(LPWSTR *ppszFile);
|
|
STDMETHODIMP GetSize(LPDWORD pcbFile, LPDWORD pcbAllocated, LPDWORD pcbFreed, LPDWORD pcbStreams);
|
|
STDMETHODIMP Repair(void) { return _CheckForCorruption(); }
|
|
|
|
//----------------------------------------------------------------------
|
|
// Fast-Heap Methods
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP HeapFree(LPVOID pvBuffer);
|
|
STDMETHODIMP HeapAllocate(DWORD dwFlags, DWORD cbSize, LPVOID *ppBuffer) {
|
|
*ppBuffer = PHeapAllocate(dwFlags, cbSize);
|
|
return(*ppBuffer ? S_OK : E_OUTOFMEMORY);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// General Utility Methods
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP Compact(IDatabaseProgress *pProgress, COMPACTFLAGS dwFlags);
|
|
STDMETHODIMP GenerateId(LPDWORD pdwId);
|
|
STDMETHODIMP GetClientCount(LPDWORD pcClients);
|
|
|
|
//----------------------------------------------------------------------
|
|
// CDatabase Members
|
|
//----------------------------------------------------------------------
|
|
HRESULT StreamCompareDatabase(CDatabaseStream *pStream, IDatabase *pDatabase);
|
|
HRESULT GetStreamAddress(CDatabaseStream *pStream, LPFILEADDRESS pfaStream);
|
|
HRESULT StreamRead(CDatabaseStream *pStream, LPVOID pvData, ULONG cbWanted, ULONG *pcbRead);
|
|
HRESULT StreamWrite(CDatabaseStream *pStream, const void *pvData, ULONG cb, ULONG *pcbWrote);
|
|
HRESULT StreamSeek(CDatabaseStream *pStream, LARGE_INTEGER liMove, DWORD dwOrigin, ULARGE_INTEGER *pulNew);
|
|
HRESULT StreamRelease(CDatabaseStream *pStream);
|
|
HRESULT StreamGetAddress(CDatabaseStream *pStream, LPFILEADDRESS pfaStart);
|
|
HRESULT DoInProcessInvoke(INVOKETYPE tyInvoke);
|
|
#ifdef BACKGROUND_MONITOR
|
|
HRESULT DoBackgroundMonitor(void);
|
|
#endif
|
|
HRESULT BindRecord(LPRECORDMAP pMap, LPVOID pBinding);
|
|
LPVOID PHeapAllocate(DWORD dwFlags, DWORD cbSize);
|
|
|
|
//----------------------------------------------------------------------
|
|
// AllocateBinding
|
|
//----------------------------------------------------------------------
|
|
HRESULT AllocateBinding(LPVOID *ppBinding) {
|
|
*ppBinding = PHeapAllocate(HEAP_ZERO_MEMORY, m_pSchema->cbBinding);
|
|
return(*ppBinding ? S_OK : E_OUTOFMEMORY);
|
|
}
|
|
|
|
private:
|
|
//----------------------------------------------------------------------
|
|
// General Btree Methods
|
|
//----------------------------------------------------------------------
|
|
HRESULT _IsLeafChain(LPCHAINBLOCK pChain);
|
|
HRESULT _AdjustParentNodeCount(INDEXORDINAL iIndex, FILEADDRESS faChain, LONG lCount);
|
|
HRESULT _ValidateFileVersions(OPENDATABASEFLAGS dwFlags);
|
|
HRESULT _ResetTableHeader(void);
|
|
HRESULT _RemoveClientFromArray(DWORD dwProcessId, DWORD_PTR pDB);
|
|
HRESULT _BuildQueryTable(void);
|
|
HRESULT _StreamSychronize(CDatabaseStream *pStream);
|
|
HRESULT _InitializeExtension(OPENDATABASEFLAGS dwFlags, IDatabaseExtension *pExtension);
|
|
HRESULT _GetRecordMap(BOOL fGoCorrupt, LPRECORDBLOCK pBlock, LPRECORDMAP pMap);
|
|
|
|
//----------------------------------------------------------------------
|
|
// File Mapping / View Utilities
|
|
//----------------------------------------------------------------------
|
|
HRESULT _InitializeFileViews(void);
|
|
HRESULT _CloseFileViews(BOOL fFlush);
|
|
HRESULT _AllocateSpecialView(FILEADDRESS faView, DWORD cbView, LPFILEVIEW *ppSpecial);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Btree Search / Virtual Scrolling
|
|
//----------------------------------------------------------------------
|
|
HRESULT _GetChainByIndex(INDEXORDINAL iIndex, ROWORDINAL iRow, LPFILEADDRESS pfaChain, LPNODEINDEX piNode);
|
|
HRESULT _CompareBinding(INDEXORDINAL iIndex, DWORD cColumns, LPVOID pBinding, FILEADDRESS faRecord, INT *pnCompare);
|
|
HRESULT _IsVisible(HQUERY hQuery, LPVOID pBinding);
|
|
HRESULT _PartialIndexCompare(INDEXORDINAL iIndex, DWORD cColumns, LPVOID pBinding, LPCHAINBLOCK *ppChain, LPNODEINDEX piNode, LPROWORDINAL piRow);
|
|
HRESULT _FindRecord(INDEXORDINAL iIndex, DWORD cColumns, LPVOID pBinding, LPFILEADDRESS pfaChain, LPNODEINDEX piNode, LPROWORDINAL piRow=NULL, INT *pnCompare=NULL);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Btree Deletion Methods
|
|
//----------------------------------------------------------------------
|
|
HRESULT _CollapseChain(LPCHAINBLOCK pChain, NODEINDEX iDelete);
|
|
HRESULT _ExpandChain(LPCHAINBLOCK pChain, NODEINDEX iNode);
|
|
HRESULT _IndexDeleteRecord(INDEXORDINAL iIndex, FILEADDRESS faDelete, NODEINDEX iDelete);
|
|
HRESULT _GetRightSibling(FILEADDRESS faCurrent, LPCHAINBLOCK *ppSibling);
|
|
HRESULT _GetLeftSibling(FILEADDRESS faCurrent, LPCHAINBLOCK *ppSibling);
|
|
HRESULT _GetInOrderSuccessor(FILEADDRESS faStart, NODEINDEX iDelete, LPCHAINBLOCK *ppSuccessor);
|
|
HRESULT _DecideHowToDelete(LPFILEADDRESS pfaShare, FILEADDRESS faDelete, CHAINDELETETYPE *ptyDelete, CHAINSHARETYPE *ptyShare);
|
|
HRESULT _ChainDeleteShare(INDEXORDINAL iIndex, FILEADDRESS faDelete, FILEADDRESS faShare, CHAINSHARETYPE tyShare);
|
|
HRESULT _ChainDeleteCoalesce(INDEXORDINAL iIndex, FILEADDRESS faDelete, FILEADDRESS faShare, CHAINSHARETYPE tyShare);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Btree Insertion Methods
|
|
//----------------------------------------------------------------------
|
|
HRESULT _IndexInsertRecord(INDEXORDINAL iIndex, FILEADDRESS faChain, FILEADDRESS faRecord, LPNODEINDEX piNode, INT nCompare);
|
|
HRESULT _ChainInsert(INDEXORDINAL iIndex, LPCHAINBLOCK pChain, LPCHAINNODE pNode, LPNODEINDEX piNodeIndex);
|
|
HRESULT _SplitChainInsert(INDEXORDINAL iIndex, FILEADDRESS faLeaf);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Record Persistence Methods
|
|
//----------------------------------------------------------------------
|
|
HRESULT _GetRecordSize(LPVOID pBinding, LPRECORDMAP pMap);
|
|
HRESULT _SaveRecord(LPRECORDBLOCK pBlock, LPRECORDMAP pMap, LPVOID pBinding);
|
|
HRESULT _ReadRecord(FILEADDRESS faRecord, LPVOID pBinding, BOOL fInternal=FALSE);
|
|
HRESULT _LinkRecordIntoTable(LPRECORDMAP pMap, LPVOID pBinding, BYTE bVersion, LPFILEADDRESS pfaRecord);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Notification / Invoke Methods
|
|
//----------------------------------------------------------------------
|
|
HRESULT _DispatchInvoke(INVOKETYPE tyInvoke);
|
|
HRESULT _DispatchNotification(HTRANSACTION hTransaction);
|
|
HRESULT _LogTransaction(TRANSACTIONTYPE tyTransaction, INDEXORDINAL iIndex, LPORDINALLIST pOrdinals, FILEADDRESS faRecord1, FILEADDRESS faRecord2);
|
|
HRESULT _CloseNotificationWindow(LPNOTIFYRECIPIENT pRecipient);
|
|
HRESULT _FindClient(DWORD dwProcessId, DWORD_PTR dwDB, LPDWORD piClient, LPCLIENTENTRY *ppClient);
|
|
HRESULT _FindNotifyRecipient(DWORD iClient, IDatabaseNotify *pNotify, LPDWORD piRecipient, LPNOTIFYRECIPIENT *ppRecipient);
|
|
HRESULT _DispatchPendingNotifications(void);
|
|
HRESULT _AdjustNotifyCounts(LPNOTIFYRECIPIENT pRecipient, LONG lChange);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Rowset Support Methods
|
|
//----------------------------------------------------------------------
|
|
HRESULT _AdjustOpenRowsets(INDEXORDINAL iIndex, ROWORDINAL iRow, OPERATIONTYPE tyOperation);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Alloctation Methods
|
|
//----------------------------------------------------------------------
|
|
HRESULT _MarkBlock(BLOCKTYPE tyBlock, FILEADDRESS faBlock, DWORD cbBlock, LPVOID *ppvBlock);
|
|
HRESULT _ReuseFixedFreeBlock(LPFILEADDRESS pfaFreeHead, BLOCKTYPE tyBlock, DWORD cbBlock, LPVOID *ppvBlock);
|
|
HRESULT _FreeRecordStorage(OPERATIONTYPE tyOperation, FILEADDRESS faRecord);
|
|
HRESULT _FreeStreamStorage(FILEADDRESS faStart);
|
|
HRESULT _SetStorageSize(DWORD cbSize);
|
|
HRESULT _AllocateBlock(BLOCKTYPE tyBlock, DWORD cbExtra, LPVOID *ppBlock);
|
|
HRESULT _AllocateFromPage(BLOCKTYPE tyBlock, LPALLOCATEPAGE pPage, DWORD cbPage, DWORD cbBlock, LPVOID *ppvBlock);
|
|
HRESULT _FreeBlock(BLOCKTYPE tyBlock, FILEADDRESS faBlock);
|
|
HRESULT _AllocatePage(DWORD cbPage, LPFILEADDRESS pfaAddress);
|
|
HRESULT _FreeIndex(FILEADDRESS faChain);
|
|
HRESULT _CopyRecord(FILEADDRESS faRecord, LPFILEADDRESS pfaCopy);
|
|
HRESULT _FreeTransactBlock(LPTRANSACTIONBLOCK pTransact);
|
|
HRESULT _CleanupTransactList(void);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Compaction Helpers
|
|
//----------------------------------------------------------------------
|
|
HRESULT _CompactMoveRecordStreams(CDatabase *pDstDB, LPVOID pBinding);
|
|
HRESULT _CompactMoveOpenDeletedStreams(CDatabase *pDstDB);
|
|
HRESULT _CompactTransferFilters(CDatabase *pDstDB);
|
|
HRESULT _CompactInsertRecord(LPVOID pBinding);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Index Management
|
|
//----------------------------------------------------------------------
|
|
HRESULT _ValidateIndex(INDEXORDINAL iIndex, FILEADDRESS faChain, ULONG cLeftNodes, ULONG *pcRecords);
|
|
HRESULT _RebuildIndex(INDEXORDINAL iIndex);
|
|
HRESULT _RecursiveRebuildIndex(INDEXORDINAL iIndex, FILEADDRESS faCurrent, LPVOID pBinding, LPDWORD pcRecords);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Corruption Validation and Repair Methods
|
|
//----------------------------------------------------------------------
|
|
HRESULT _HandleOpenMovedFile(void);
|
|
HRESULT _SetCorrupt(BOOL fGoCorrupt, INT nLine, CORRUPTREASON tyReason, BLOCKTYPE tyBlock, FILEADDRESS faExpected, FILEADDRESS faActual, DWORD cbBlock);
|
|
HRESULT _CheckForCorruption(void);
|
|
HRESULT _GetBlock(BLOCKTYPE tyExpected, FILEADDRESS faBlock, LPVOID *ppvBlock, LPMARKBLOCK pMark=NULL, BOOL fGoCorrupt=TRUE);
|
|
HRESULT _ValidateAndRepairRecord(LPRECORDMAP pMap);
|
|
HRESULT _ValidateStream(FILEADDRESS faStart);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Private Debug Methods
|
|
//----------------------------------------------------------------------
|
|
IF_DEBUG(HRESULT _DebugValidateRecordFormat(void));
|
|
IF_DEBUG(HRESULT _DebugValidateUnrefedRecord(FILEADDRESS farecord));
|
|
IF_DEBUG(HRESULT _DebugValidateIndexUnrefedRecord(FILEADDRESS faChain, FILEADDRESS faRecord));
|
|
|
|
private:
|
|
//----------------------------------------------------------------------
|
|
// Prototypes
|
|
//----------------------------------------------------------------------
|
|
LONG m_cRef;
|
|
LONG m_cExtRefs;
|
|
HANDLE m_hMutex;
|
|
#ifdef BACKGROUND_MONITOR
|
|
HMONITORDB m_hMonitor;
|
|
#endif
|
|
DWORD m_dwProcessId;
|
|
BOOL m_fDirty;
|
|
LPCTABLESCHEMA m_pSchema;
|
|
LPSTORAGEINFO m_pStorage;
|
|
LPTABLEHEADER m_pHeader;
|
|
LPSHAREDDATABASE m_pShare;
|
|
HANDLE m_hHeap;
|
|
BYTE m_fDeconstruct;
|
|
BYTE m_fInMoveFile;
|
|
BYTE m_fExclusive;
|
|
BYTE m_fCompactYield;
|
|
DWORD m_dwQueryVersion;
|
|
HQUERY m_rghFilter[CMAX_INDEXES];
|
|
IDatabaseExtension *m_pExtension;
|
|
IUnknown *m_pUnkRelease;
|
|
LPBYTE m_rgpRecycle[CC_HEAP_BUCKETS];
|
|
CRITICAL_SECTION m_csHeap;
|
|
IF_DEBUG(DWORD m_cbHeapAlloc);
|
|
IF_DEBUG(DWORD m_cbHeapFree);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Friend
|
|
//----------------------------------------------------------------------
|
|
friend CDatabaseQuery;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CDatabaseQuery
|
|
//--------------------------------------------------------------------------
|
|
class CDatabaseQuery : public IDatabaseQuery
|
|
{
|
|
public:
|
|
//----------------------------------------------------------------------
|
|
// Construction
|
|
//----------------------------------------------------------------------
|
|
CDatabaseQuery(void) {
|
|
TraceCall("CDatabaseQuery::CDatabaseQuery");
|
|
m_cRef = 1;
|
|
m_hQuery = NULL;
|
|
m_pDatabase = NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// De-Construction
|
|
//----------------------------------------------------------------------
|
|
~CDatabaseQuery(void) {
|
|
TraceCall("CDatabaseQuery::~CDatabaseQuery");
|
|
CloseQuery(&m_hQuery, m_pDatabase);
|
|
SafeRelease(m_pDatabase);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// IUnknown Members
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv) {
|
|
TraceCall("CDatabaseQuery::QueryInterface");
|
|
*ppv = NULL;
|
|
if (IID_IUnknown == riid)
|
|
*ppv = (IUnknown *)this;
|
|
else if (IID_IDatabaseQuery == riid)
|
|
*ppv = (IDatabaseQuery *)this;
|
|
else
|
|
return TraceResult(E_NOINTERFACE);
|
|
((IUnknown *)*ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// IDatabaseQuery::AddRef
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) AddRef(void) {
|
|
TraceCall("CDatabaseQuery::AddRef");
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// IDatabaseQuery::Release
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) Release(void) {
|
|
TraceCall("CDatabaseQuery::Release");
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CDatabaseQuery::Initialize
|
|
//----------------------------------------------------------------------
|
|
HRESULT Initialize(IDatabase *pDatabase, LPCSTR pszQuery) {
|
|
TraceCall("CDatabaseQuery::Initialize");
|
|
pDatabase->QueryInterface(IID_CDatabase, (LPVOID *)&m_pDatabase);
|
|
return(ParseQuery(pszQuery, m_pDatabase->m_pSchema, &m_hQuery, m_pDatabase));
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// CDatabaseQuery::Evaluate
|
|
//----------------------------------------------------------------------
|
|
STDMETHODIMP Evaluate(LPVOID pBinding) {
|
|
TraceCall("CDatabaseQuery::Evaluate");
|
|
return(EvaluateQuery(m_hQuery, pBinding, m_pDatabase->m_pSchema, m_pDatabase, m_pDatabase->m_pExtension));
|
|
}
|
|
|
|
private:
|
|
//----------------------------------------------------------------------
|
|
// Private Data
|
|
//----------------------------------------------------------------------
|
|
LONG m_cRef;
|
|
HQUERY m_hQuery;
|
|
CDatabase *m_pDatabase;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// PTagFromOrdinal
|
|
//--------------------------------------------------------------------------
|
|
inline LPCOLUMNTAG PTagFromOrdinal(LPRECORDMAP pMap, COLUMNORDINAL iColumn);
|