/// <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>
        /// 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();
            }
        }