/// <summary> /// Updates this record values. /// </summary> /// <param name="rowValues">Row new values.</param> private void UpdateRecord(object[] rowValues) { bool unlock = true; // Table is already locked, don't lock it if (m_pOwnerDb.TableLocked) { unlock = false; } else { m_pOwnerDb.LockTable(15); } // Create new record byte[] rowData = CreateRecord(m_pOwnerDb, rowValues); DataPage[] dataPages = DataPages; // Clear old data ?? do we need that // for(int i=0;i<dataPages.Length;i++){ // dataPages[i].Data = new byte[1000]; // } // We haven't enough room to store row, get needed data pages if ((int) Math.Ceiling(rowData.Length/(double) m_pOwnerDb.DataPageDataAreaSize) > dataPages.Length) { int dataPagesNeeded = (int) Math.Ceiling(rowData.Length/(double) m_pOwnerDb.DataPageDataAreaSize) - dataPages.Length; DataPage[] additionalDataPages = m_pOwnerDb.GetDataPages(dataPages[dataPages.Length - 1].Pointer, dataPagesNeeded); // Append new data pages to existing data pages chain dataPages[dataPages.Length - 1].NextDataPagePointer = additionalDataPages[0].Pointer; DataPage[] newVal = new DataPage[dataPages.Length + additionalDataPages.Length]; Array.Copy(dataPages, 0, newVal, 0, dataPages.Length); Array.Copy(additionalDataPages, 0, newVal, dataPages.Length, additionalDataPages.Length); dataPages = newVal; } // Store new record DbFile.StoreDataToDataPages(m_pOwnerDb.DataPageDataAreaSize, rowData, dataPages); // Update row info ParseRowInfo(); if (unlock) { m_pOwnerDb.UnlockTable(); } }
/// <summary> /// Default constructor. /// </summary> /// <param name="ownerDb">Table that owns this row.</param> /// <param name="rowStartDataPage">Data page on what row starts.</param> internal LDB_Record(DbFile ownerDb, DataPage rowStartDataPage) { m_pOwnerDb = ownerDb; m_pDataPage = rowStartDataPage; ParseRowInfo(); }
/// <summary> /// Gets specified column data. /// </summary> /// <param name="columnIndex">Column index.</param> /// <returns></returns> private object GetColumnData(int columnIndex) { // Get column data start offset int columnStartOffset = 4*m_pOwnerDb.Columns.Count; for (int i = 0; i < columnIndex; i++) { columnStartOffset += m_ColumnValueSize[i]; } int dataLength = m_ColumnValueSize[columnIndex]; int startDataPage = (int) Math.Floor(columnStartOffset/(double) m_pOwnerDb.DataPageDataAreaSize); int offsetInStartDataPage = columnStartOffset - (startDataPage*m_pOwnerDb.DataPageDataAreaSize); int dataOffset = 0; int currentDataPageIndex = 0; byte[] columnData = new byte[dataLength]; DataPage currentDataPage = DataPage; while (dataOffset < dataLength) { // We haven't reached to data page on what data starts, just go to next continuing data page if (currentDataPageIndex < startDataPage) { // Get next continuing data page currentDataPage = new DataPage(m_pOwnerDb.DataPageDataAreaSize, m_pOwnerDb, currentDataPage.NextDataPagePointer); currentDataPageIndex++; } // We need all this data page data + addtitional data pages data else if ((dataLength - dataOffset + offsetInStartDataPage) > currentDataPage.StoredDataLength) { currentDataPage.ReadData(columnData, dataOffset, m_pOwnerDb.DataPageDataAreaSize - offsetInStartDataPage, offsetInStartDataPage); dataOffset += m_pOwnerDb.DataPageDataAreaSize - offsetInStartDataPage; // Get next continuing data page currentDataPage = new DataPage(m_pOwnerDb.DataPageDataAreaSize, m_pOwnerDb, currentDataPage.NextDataPagePointer); currentDataPageIndex++; offsetInStartDataPage = 0; } // This data page has all data we need else { currentDataPage.ReadData(columnData, dataOffset, dataLength - dataOffset, offsetInStartDataPage); dataOffset += dataLength - dataOffset; offsetInStartDataPage = 0; } } // Convert to column data type return ConvertFromInternalData(m_pOwnerDb.Columns[columnIndex], columnData); }
/// <summary> /// Gets specified number of free data pages. If free data pages won't exist, creates new ones. /// Data pages are marked as used and OwnerDataPagePointer and NextDataPagePointer is set as needed. /// </summary> /// <param name="ownerDataPagePointer">Owner data page pointer that own first requested data page. If no owner then this value is 0.</param> /// <param name="count">Number of data pages wanted.</param> internal DataPage[] GetDataPages(long ownerDataPagePointer, int count) { if (!TableLocked) { throw new Exception("Table must be locked to acess GetDataPages() method !"); } ArrayList freeDataPages = new ArrayList(); // Get free data pages count from table header byte[] freeDataPagesCount = new byte[8]; SetFilePosition(52); ReadFromFile(freeDataPagesCount, 0, freeDataPagesCount.Length); long nFreeDataPages = ldb_Utils.ByteToLong(freeDataPagesCount, 0); // We have plenty free data pages and enough for count requested, find requested count free data pages if (nFreeDataPages > 1000 && nFreeDataPages > count) { long nextDataPagePointer = m_DatapagesStartOffset + 1; while (freeDataPages.Count < count) { DataPage dataPage = new DataPage(m_DataPageDataAreaSize, this, nextDataPagePointer); if (!dataPage.Used) { dataPage.Used = true; freeDataPages.Add(dataPage); } nextDataPagePointer += m_DataPageDataAreaSize + 33; } // Decrease free data pages count in table header SetFilePosition(52); ReadFromFile(ldb_Utils.LongToByte(nFreeDataPages - count), 0, 8); } // Just create new data pages else { for (int i = 0; i < count; i++) { byte[] dataPage = DataPage.CreateDataPage(m_DataPageDataAreaSize, true, 0, 0, 0, new byte[m_DataPageDataAreaSize]); GoToFileEnd(); long dataPageStartPointer = GetFilePosition(); WriteToFile(dataPage, 0, dataPage.Length); freeDataPages.Add(new DataPage(m_DataPageDataAreaSize, this, dataPageStartPointer)); } } // Relate data pages (chain) for (int i = 0; i < freeDataPages.Count; i++) { // First data page if (i == 0) { // Owner data page poitner specified for first data page if (ownerDataPagePointer > 0) { ((DataPage) freeDataPages[i]).OwnerDataPagePointer = ownerDataPagePointer; } // There is continuing data page if (freeDataPages.Count > 1) { ((DataPage) freeDataPages[i]).NextDataPagePointer = ((DataPage) freeDataPages[i + 1]).Pointer; } } // Last data page else if (i == (freeDataPages.Count - 1)) { ((DataPage) freeDataPages[i]).OwnerDataPagePointer = ((DataPage) freeDataPages[i - 1]).Pointer; } // Middle range data page else { ((DataPage) freeDataPages[i]).OwnerDataPagePointer = ((DataPage) freeDataPages[i - 1]).Pointer; ((DataPage) freeDataPages[i]).NextDataPagePointer = ((DataPage) freeDataPages[i + 1]).Pointer; } } DataPage[] retVal = new DataPage[freeDataPages.Count]; freeDataPages.CopyTo(retVal); return retVal; }
/// <summary> /// Stores data to specified data pages. /// </summary> /// <param name="dataPageDataAreaSize">Data page data area size.</param> /// <param name="data">Data to store.</param> /// <param name="dataPages">Data pages where to store data.</param> internal static void StoreDataToDataPages(int dataPageDataAreaSize, byte[] data, DataPage[] dataPages) { if ((int) Math.Ceiling(data.Length/(double) dataPageDataAreaSize) > dataPages.Length) { throw new Exception("There isn't enough data pages to store data ! Data needs '" + (int) Math.Ceiling(data.Length/(double) dataPageDataAreaSize) + "' , but available '" + dataPages.Length + "'."); } //--- Store data to data page(s) -----------------------// long position = 0; for (int i = 0; i < dataPages.Length; i++) { if ((data.Length - position) > dataPageDataAreaSize) { byte[] d = new byte[dataPageDataAreaSize]; Array.Copy(data, position, d, 0, d.Length); dataPages[i].WriteData(d); position += dataPageDataAreaSize; } else { byte[] d = new byte[data.Length - position]; Array.Copy(data, position, d, 0, d.Length); dataPages[i].WriteData(d); } } //------------------------------------------------------// }
/* /// <summary> /// Locks current record. /// </summary> public void LockRecord() { if(!this.IsDatabaseOpen){ throw new Exception("Database isn't open, please open database first !"); } } */ /* /// <summary> /// Unlocks current record. /// </summary> public void UnlockRecord() { if(!this.IsDatabaseOpen){ throw new Exception("Database isn't open, please open database first !"); } } */ /// <summary> /// Gets next record. Returns true if end of file reached and there are no more records. /// </summary> /// <returns>Returns true if end of file reached and there are no more records.</returns> public bool NextRecord() { if (!IsDatabaseOpen) { throw new Exception("Database isn't open, please open database first !"); } //--- Find next record ---------------------------------------------------// long nextRowStartOffset = 0; if (m_pCurrentRecord == null) { nextRowStartOffset = m_DatapagesStartOffset; } else { nextRowStartOffset = m_pCurrentRecord.DataPage.Pointer + m_DataPageDataAreaSize + 33; } while (true) { if (m_FileLength > nextRowStartOffset) { DataPage dataPage = new DataPage(m_DataPageDataAreaSize, this, nextRowStartOffset); // We want datapage with used space if (dataPage.Used && dataPage.OwnerDataPagePointer < 1) { m_pCurrentRecord = new LDB_Record(this, dataPage); break; } } else { return true; } nextRowStartOffset += m_DataPageDataAreaSize + 33; } //-------------------------------------------------------------------------// return false; }
/// <summary> /// Gets specified column data. /// </summary> /// <param name="columnIndex">Column index.</param> /// <returns></returns> private object GetColumnData(int columnIndex) { // Get column data start offset int columnStartOffset = 4 * m_pOwnerDb.Columns.Count; for (int i = 0; i < columnIndex; i++) { columnStartOffset += m_ColumnValueSize[i]; } int dataLength = m_ColumnValueSize[columnIndex]; int startDataPage = (int)Math.Floor(columnStartOffset / (double)m_pOwnerDb.DataPageDataAreaSize); int offsetInStartDataPage = columnStartOffset - (startDataPage * m_pOwnerDb.DataPageDataAreaSize); int dataOffset = 0; int currentDataPageIndex = 0; byte[] columnData = new byte[dataLength]; DataPage currentDataPage = DataPage; while (dataOffset < dataLength) { // We haven't reached to data page on what data starts, just go to next continuing data page if (currentDataPageIndex < startDataPage) { // Get next continuing data page currentDataPage = new DataPage(m_pOwnerDb.DataPageDataAreaSize, m_pOwnerDb, currentDataPage.NextDataPagePointer); currentDataPageIndex++; } // We need all this data page data + addtitional data pages data else if ((dataLength - dataOffset + offsetInStartDataPage) > currentDataPage.StoredDataLength) { currentDataPage.ReadData(columnData, dataOffset, m_pOwnerDb.DataPageDataAreaSize - offsetInStartDataPage, offsetInStartDataPage); dataOffset += m_pOwnerDb.DataPageDataAreaSize - offsetInStartDataPage; // Get next continuing data page currentDataPage = new DataPage(m_pOwnerDb.DataPageDataAreaSize, m_pOwnerDb, currentDataPage.NextDataPagePointer); currentDataPageIndex++; offsetInStartDataPage = 0; } // This data page has all data we need else { currentDataPage.ReadData(columnData, dataOffset, dataLength - dataOffset, offsetInStartDataPage); dataOffset += dataLength - dataOffset; offsetInStartDataPage = 0; } } // Convert to column data type return(ConvertFromInternalData(m_pOwnerDb.Columns[columnIndex], columnData)); }
/// <summary> /// Gets specified number of free data pages. If free data pages won't exist, creates new ones. /// Data pages are marked as used and OwnerDataPagePointer and NextDataPagePointer is set as needed. /// </summary> /// <param name="ownerDataPagePointer">Owner data page pointer that own first requested data page. If no owner then this value is 0.</param> /// <param name="count">Number of data pages wanted.</param> internal DataPage[] GetDataPages(long ownerDataPagePointer, int count) { if (!TableLocked) { throw new Exception("Table must be locked to acess GetDataPages() method !"); } ArrayList freeDataPages = new ArrayList(); // Get free data pages count from table header byte[] freeDataPagesCount = new byte[8]; SetFilePosition(52); ReadFromFile(freeDataPagesCount, 0, freeDataPagesCount.Length); long nFreeDataPages = ldb_Utils.ByteToLong(freeDataPagesCount, 0); // We have plenty free data pages and enough for count requested, find requested count free data pages if (nFreeDataPages > 1000 && nFreeDataPages > count) { long nextDataPagePointer = m_DatapagesStartOffset + 1; while (freeDataPages.Count < count) { DataPage dataPage = new DataPage(m_DataPageDataAreaSize, this, nextDataPagePointer); if (!dataPage.Used) { dataPage.Used = true; freeDataPages.Add(dataPage); } nextDataPagePointer += m_DataPageDataAreaSize + 33; } // Decrease free data pages count in table header SetFilePosition(52); ReadFromFile(ldb_Utils.LongToByte(nFreeDataPages - count), 0, 8); } // Just create new data pages else { for (int i = 0; i < count; i++) { byte[] dataPage = DataPage.CreateDataPage(m_DataPageDataAreaSize, true, 0, 0, 0, new byte[m_DataPageDataAreaSize]); GoToFileEnd(); long dataPageStartPointer = GetFilePosition(); WriteToFile(dataPage, 0, dataPage.Length); freeDataPages.Add(new DataPage(m_DataPageDataAreaSize, this, dataPageStartPointer)); } } // Relate data pages (chain) for (int i = 0; i < freeDataPages.Count; i++) { // First data page if (i == 0) { // Owner data page poitner specified for first data page if (ownerDataPagePointer > 0) { ((DataPage)freeDataPages[i]).OwnerDataPagePointer = ownerDataPagePointer; } // There is continuing data page if (freeDataPages.Count > 1) { ((DataPage)freeDataPages[i]).NextDataPagePointer = ((DataPage)freeDataPages[i + 1]).Pointer; } } // Last data page else if (i == (freeDataPages.Count - 1)) { ((DataPage)freeDataPages[i]).OwnerDataPagePointer = ((DataPage)freeDataPages[i - 1]).Pointer; } // Middle range data page else { ((DataPage)freeDataPages[i]).OwnerDataPagePointer = ((DataPage)freeDataPages[i - 1]).Pointer; ((DataPage)freeDataPages[i]).NextDataPagePointer = ((DataPage)freeDataPages[i + 1]).Pointer; } } DataPage[] retVal = new DataPage[freeDataPages.Count]; freeDataPages.CopyTo(retVal); return(retVal); }