/// <summary> /// Gets or sets specified data column value. /// </summary> /// <param name="columnIndex">Zero based column index.</param> /// <returns></returns> public object this[int columnIndex] { /* Fixed record structure: * 1 byte - specified is row is used or free space * u - used * f - free space * x bytes - columns data * 2 bytes - CRLF */ get{ if (columnIndex < 0) { throw new Exception("The columnIndex can't be negative value !"); } if (columnIndex > m_ColumnCount) { throw new Exception("The columnIndex out of columns count !"); } return(ConvertFromInternalData(m_ColumnDataTypes[columnIndex], m_RowData, m_ColumnDataStartOffsets[columnIndex], m_ColumnDataSizes[columnIndex])); } set{ if (columnIndex < 0) { throw new Exception("The columnIndex can't be negative value !"); } if (columnIndex > m_ColumnCount) { throw new Exception("The columnIndex out of columns count !"); } byte[] val = LDB_Record.ConvertToInternalData(m_pOwnerDb.Columns[columnIndex], value); // Check that value won't exceed maximum cloumn allowed size if (val.Length > m_ColumnDataSizes[columnIndex]) { throw new Exception("Value exceeds maximum allowed value for column '" + m_pOwnerDb.Columns[columnIndex].ColumnName + "' !"); } // TODO: String, string must be char(0) terminated and padded to column length if (m_ColumnDataTypes[columnIndex] == LDB_DataType.String) { throw new Exception("TODO: String not implemented !"); } // Update value in database file m_pOwnerDb.WriteToFile(m_Pointer + m_ColumnDataStartOffsets[columnIndex], val, 0, val.Length); // Update value in buffer Array.Copy(val, 0, m_RowData, m_ColumnDataStartOffsets[columnIndex], val.Length); } }
/// <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> * /// Locks current record. * /// </summary> * public void LockRecord() * { * if(!this.IsDatabaseOpen){ * throw new Exception("Database isn't open, please open database first !"); * } * * } */ #endregion #region method UnlockRecord /* * /// <summary> * /// Unlocks current record. * /// </summary> * public void UnlockRecord() * { * if(!this.IsDatabaseOpen){ * throw new Exception("Database isn't open, please open database first !"); * } * * } */ #endregion #region method NextRecord /// <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); }
/// <summary> /// Appends new record to table. /// </summary> public void AppendRecord(object[] values) { if (!this.IsDatabaseOpen) { throw new Exception("Database isn't open, please open database first !"); } if (m_pColumns.Count != values.Length) { throw new Exception("Each column must have corresponding value !"); } bool unlock = true; // Table is already locked, don't lock it if (this.TableLocked) { unlock = false; } else { LockTable(15); } // Construct record data byte[] record = LDB_Record.CreateRecord(this, values); // Get free data pages DataPage[] dataPages = GetDataPages(0, (int)Math.Ceiling(record.Length / (double)m_DataPageDataAreaSize)); DbFile.StoreDataToDataPages(m_DataPageDataAreaSize, record, dataPages); if (unlock) { UnlockTable(); } }
/// <summary> /// Appends new record to table. /// </summary> public void AppendRecord(object[] values) { if (!this.IsDatabaseOpen) { throw new Exception("Database isn't open, please open database first !"); } if (m_pColumns.Count != values.Length) { throw new Exception("Each column must have corresponding value !"); } bool unlock = true; // Table is already locked, don't lock it if (this.TableLocked) { unlock = false; } else { LockTable(15); } /* Fixed record structure: * 1 byte - specified is row is used or free space * u - used * f - free space * x bytes - columns data * 2 bytes - CRLF */ int rowLength = 1 + 2; for (int i = 0; i < m_pColumns.Count; i++) { rowLength += m_pColumns[i].ColumnSize; } int position = 1; byte[] record = new byte[rowLength]; record[0] = (int)'u'; record[rowLength - 2] = (int)'\r'; record[rowLength - 1] = (int)'\n'; for (int i = 0; i < values.Length; i++) { byte[] columnData = LDB_Record.ConvertToInternalData(m_pColumns[i], values[i]); // Check that column won't exceed maximum length. if (columnData.Length > m_pColumns[i].ColumnSize) { throw new Exception("Column '" + m_pColumns[i] + "' exceeds maximum value length !"); } Array.Copy(columnData, 0, record, position, columnData.Length); position += columnData.Length; } // Find free row byte[] freeRowsBuffer = new byte[4]; ReadFromFile(52, freeRowsBuffer, 0, freeRowsBuffer.Length); int freeRows = ldb_Utils.ByteToInt(freeRowsBuffer, 0); // There are plenty free rows, find first if (freeRows > 100) { //--- Find free record ---------------------------------------------------// long nextRowStartOffset = m_RowsStartOffset; long rowOffset = 0; byte[] rowData = new byte[m_RowLength]; while (true) { ReadFromFile(nextRowStartOffset, rowData, 0, m_RowLength); // We want used row if (rowData[0] == 'f') { rowOffset = nextRowStartOffset; break; } nextRowStartOffset += m_RowLength; } //-------------------------------------------------------------------------// // Write new record to file WriteToFile(rowOffset, record, 0, record.Length); // Update free rows count WriteToFile(52, ldb_Utils.IntToByte(freeRows - 1), 0, 4); } // There are few empty rows, just append it else { AppendToFile(record, 0, record.Length); } if (unlock) { UnlockTable(); } }
/// <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; }