/// <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>
        /// 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 = LDB_Record.CreateRecord(m_pOwnerDb,rowValues);

            DataPage[] dataPages = this.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>
        /// 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 = this.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 - (int)dataOffset,offsetInStartDataPage);
                    dataOffset += dataLength - (int)dataOffset;

                    offsetInStartDataPage = 0;
                }
            }

            // Convert to column data type
            return ConvertFromInternalData(m_pOwnerDb.Columns[columnIndex],columnData);
        }
Example #4
0
        /// <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(!this.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;
        }
Example #5
0
        /// <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);
                }
            }
            //------------------------------------------------------//
        }
Example #6
0
        /// <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(!this.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;
        }