/// <summary> /// Returns the Record at the specified Offset, while also updating Position to match. /// </summary> public BtrieveRecord GetRecord(uint offset) { Position = offset; if (_cache.TryGetValue(offset, out var record)) { return(record); } using var cmd = new SqliteCommand($"SELECT data FROM data_t WHERE id = {offset}", _connection); using var reader = cmd.ExecuteReader(System.Data.CommandBehavior.KeyInfo); try { if (!reader.Read()) { return(null); } using var stream = reader.GetStream(0); var data = new byte[stream.Length]; stream.Read(data, 0, data.Length); record = new BtrieveRecord(offset, data); _cache[offset] = record; return(record); } finally { reader.Close(); } }
/// <summary> /// Inserts a new Btrieve Record. /// </summary> /// <return>Position of the newly inserted item, or 0 on failure</return> public uint Insert(byte[] record) { if (VariableLengthRecords && record.Length != RecordLength) { _logger.Warn($"Inserting variable length record of {record.Length} bytes into {FullPath}"); } if (!VariableLengthRecords && record.Length != RecordLength) { _logger.Warn( $"Btrieve Record Size Mismatch TRUNCATING. Expected Length {RecordLength}, Actual Length {record.Length}"); record = ForceSize(record, RecordLength); } using var transaction = _connection.BeginTransaction(); using var insertCmd = new SqliteCommand() { Connection = _connection }; insertCmd.Transaction = transaction; if (!InsertAutoincrementValues(transaction, record)) { transaction.Rollback(); return(0); } var sb = new StringBuilder("INSERT INTO data_t(data, "); sb.Append(string.Join(", ", Keys.Values.Select(key => key.SqliteKeyName).ToList())); sb.Append(") VALUES(@data, "); sb.Append(string.Join(", ", Keys.Values.Select(key => $"@{key.SqliteKeyName}").ToList())); sb.Append(");"); insertCmd.CommandText = sb.ToString(); insertCmd.Parameters.AddWithValue("@data", record); foreach (var key in Keys.Values) { insertCmd.Parameters.AddWithValue($"@{key.SqliteKeyName}", key.ExtractKeyInRecordToSqliteObject(record)); } int queryResult; try { queryResult = insertCmd.ExecuteNonQuery(); } catch (SqliteException ex) { _logger.Warn(ex, $"{FullPath}: Failed to insert record because {ex.Message}"); transaction.Rollback(); return(0); } var lastInsertRowId = Convert.ToUInt32(new SqliteCommand("SELECT last_insert_rowid()", _connection, transaction).ExecuteScalar()); transaction.Commit(); if (queryResult == 0) { return(0); } _cache[lastInsertRowId] = new BtrieveRecord(lastInsertRowId, record); return(lastInsertRowId); }
/// <summary> /// Updates the Record at the specified Offset. /// </summary> public bool Update(uint offset, byte[] recordData) { if (VariableLengthRecords && recordData.Length != RecordLength) { _logger.Warn($"Updating variable length record of {recordData.Length} bytes into {FullPath}"); } if (!VariableLengthRecords && recordData.Length != RecordLength) { _logger.Warn( $"Btrieve Record Size Mismatch. Expected Length {RecordLength}, Actual Length {recordData.Length}"); recordData = ForceSize(recordData, RecordLength); } using var transaction = _connection.BeginTransaction(); using var updateCmd = new SqliteCommand() { Connection = _connection, Transaction = transaction }; if (!InsertAutoincrementValues(transaction, recordData)) { transaction.Rollback(); return(false); } var sb = new StringBuilder("UPDATE data_t SET data=@data, "); sb.Append( string.Join(", ", Keys.Values.Select(key => $"{key.SqliteKeyName}=@{key.SqliteKeyName}").ToList())); sb.Append(" WHERE id=@id;"); updateCmd.CommandText = sb.ToString(); updateCmd.Parameters.AddWithValue("@id", offset); updateCmd.Parameters.AddWithValue("@data", recordData); foreach (var key in Keys.Values) { updateCmd.Parameters.AddWithValue($"@{key.SqliteKeyName}", key.ExtractKeyInRecordToSqliteObject(recordData)); } int queryResult; try { queryResult = updateCmd.ExecuteNonQuery(); } catch (SqliteException ex) { _logger.Warn(ex, $"Failed to update record because {ex.Message}"); transaction.Rollback(); return(false); } transaction.Commit(); if (queryResult == 0) { return(false); } _cache[offset] = new BtrieveRecord(offset, recordData); return(true); }