19 using System.Collections.Generic;
27 namespace Deveel.Data.Transactions {
43 EventRegistry = eventRegistry;
45 indexSet = transaction.GetTableManager().GetIndexSetForTable(tableSource);
48 var colCount = ColumnCount;
49 indexRebuilds =
new int[colCount];
58 public int ColumnCount {
79 EnsureRowIndexListCurrent();
80 return RowIndex.Count;
86 throw new ObjectDisposedException(
"Table",
"The table was disposed.");
90 int rebuildIndex = rowListRebuild;
91 int journalCount = EventRegistry.EventCount;
92 while (rebuildIndex < journalCount) {
93 var command = EventRegistry.GetEvent(rebuildIndex);
95 var rowEvent = (TableRowEvent) command;
96 var index = rowEvent.RowNumber;
101 if (!RowIndex.UniqueInsertSort(index))
102 throw new InvalidOperationException(String.Format(
"Row index already used in this table ({0})", index));
106 if (!RowIndex.RemoveSort(index))
107 throw new InvalidOperationException(
"Row index removed that wasn't in this table!");
109 throw new InvalidOperationException(String.Format(
"Table row event type {0} is invalid.", rowEvent.EventType));
117 rowListRebuild = rebuildIndex;
121 var index = columnIndexes[column];
127 int rebuildIndex = indexRebuilds[column];
128 int journalCount = EventRegistry.EventCount;
129 while (rebuildIndex < journalCount) {
130 var tableEvent = EventRegistry.GetEvent(rebuildIndex);
132 var rowEvent = (TableRowEvent) tableEvent;
135 index.
Insert(rowEvent.RowNumber);
138 index.Remove(rowEvent.RowNumber);
140 throw new InvalidOperationException(String.Format(
"Table row event type {0} is invalid.", rowEvent.EventType));
147 indexRebuilds[column] = rebuildIndex;
159 if (columnOffset < 0 || columnOffset >= ColumnCount)
160 throw new ArgumentOutOfRangeException(
"columnOffset");
162 var index = columnIndexes[columnOffset];
167 columnIndexes[columnOffset] = index;
171 EnsureColumnIndexCurrent(columnOffset);
178 if (rowIndex == null)
191 private int TableId {
205 EnsureRowIndexListCurrent();
206 var enumerator = RowIndex.GetEnumerator();
210 IEnumerator IEnumerable.GetEnumerator() {
211 return GetEnumerator();
220 if (columnIndexes != null) {
221 foreach (var columnIndex
in columnIndexes) {
222 if (columnIndex != null)
223 columnIndex.Dispose();
228 columnIndexes = null;
230 EventRegistry = null;
231 indexRebuilds = null;
240 GC.SuppressFinalize(
this);
247 throw new Exception(
"Transaction is Read only.");
250 throw new InvalidOperationException(
"Can not add row - table is read-only.");
255 }
catch (Exception ex) {
256 throw new InvalidOperationException(
257 String.Format(
"Unknown error when adding a row to the table '{0}'.",
TableInfo.
TableName), ex);
267 return new RowId(TableId, rowNum);
274 throw new Exception(
"Transaction is Read only.");
278 throw new InvalidOperationException(
"Can not update row - table is read-only.");
281 throw new ArgumentException(
"The ROWID cannot be null in an update.");
284 throw new ArgumentException(
"The row was not created from this table.");
289 throw new ArgumentException(
"The number part of the ROWID is invalid.");
299 }
catch (IOException e) {
300 throw new InvalidOperationException(
"IO Error: " + e.Message, e);
314 throw new ArgumentNullException(
"rowId");
317 throw new ArgumentException(
"The table part of the ROWID is not this table.");
319 throw new ArgumentException(
"The number part of the ROWID is not valid for remove.");
322 throw new Exception(
"Transaction is Read only.");
326 throw new InvalidOperationException(
"Can not remove row - table is Read only.");
343 EnsureRowIndexListCurrent();
346 for (
int i = 0; i < columnIndexes.Length; ++i) {
353 var updateRule = constraint.
OnUpdate;
363 var tableInfo = keyTable.TableInfo;
364 var keyCols = tableInfo.IndexOfColumns(constraint.
ColumnNames).ToArray();
365 var keyEntries = keyTable.FindKeys(keyCols, originalKey);
368 if (keyEntries.Any()) {
374 constraint.
Deferred.AsDebugString() +
375 " foreign key constraint violation on update (" +
384 foreach (
int rowNum
in keyEntries) {
385 var dataRow =
new Row(keyTable,
new RowId(keyTable.TableInfo.Id, rowNum));
386 dataRow.SetFromTable();
390 for (
int n = 0; n < keyCols.Length; ++n) {
391 dataRow.SetValue(keyCols[n], newKey[n]);
393 keyTable.UpdateRow(dataRow);
395 for (
int n = 0; n < keyCols.Length; ++n) {
396 dataRow.SetNull(keyCols[n]);
398 keyTable.UpdateRow(dataRow);
400 for (
int n = 0; n < keyCols.Length; ++n) {
401 dataRow.SetDefault(keyCols[n], context);
403 keyTable.UpdateRow(dataRow);
405 throw new Exception(
"Do not understand referential action: " + updateRule);
410 keyTable.AssertConstraints();
419 if (lastEntryRICheck == EventRegistry.EventCount)
427 using (var context = session.CreateQuery()) {
431 List<int> rowsUpdated =
new List<int>();
432 List<int> rowsDeleted =
new List<int>();
433 List<int> rowsAdded =
new List<int>();
435 var events = EventRegistry.Skip(lastEntryRICheck);
437 var rowNum = tableEvent.RowNumber;
440 rowsDeleted.Add(rowNum);
442 var index = rowsAdded.IndexOf(rowNum);
444 rowsAdded.RemoveAt(index);
447 rowsAdded.Add(rowNum);
452 rowsUpdated.Add(rowNum);
456 if (rowsDeleted.Count > 0) {
458 var foreignConstraints =
Transaction.QueryTableImportedForeignKeys(tName);
461 foreach (var constraint
in foreignConstraints) {
463 foreach (var rowNum
in rowsDeleted) {
465 var cols = tableInfo.IndexOfColumns(constraint.ForeignColumnNames).ToArray();
467 var originalKey =
new DataObject[cols.Length];
469 for (
int p = 0; p < cols.Length; ++p) {
470 originalKey[p] = GetValue(rowNum, cols[p]);
471 if (originalKey[p].IsNull) {
477 if (nullCount != cols.Length) {
479 int updateIndex = rowsUpdated.IndexOf(rowNum);
480 if (updateIndex != -1) {
482 int rowIndexAdd = rowsUpdated[updateIndex + 1];
486 bool keyChanged =
false;
487 var keyUpdatedTo =
new DataObject[cols.Length];
488 for (
int p = 0; p < cols.Length; ++p) {
489 keyUpdatedTo[p] = GetValue(rowIndexAdd, cols[p]);
490 if (originalKey[p].CompareTo(keyUpdatedTo[p]) != 0) {
497 ExecuteUpdateReferentialAction(constraint, originalKey, keyUpdatedTo, context);
505 ExecuteDeleteReferentialAction(constraint, originalKey, context);
517 if (rowsAdded.Count > 0) {
518 int[] rowIndices = rowsAdded.ToArray();
521 Transaction.CheckFieldConstraintViolations(
this, rowIndices);
531 int rollbackPoint = EventRegistry.EventCount - lastEntryRICheck;
532 if (rowListRebuild <= rollbackPoint) {
533 EventRegistry.
Rollback(rollbackPoint);
541 lastEntryRICheck = EventRegistry.EventCount;
547 var deleteRule = constraint.
OnDelete;
557 var tableInfo = keyTable.TableInfo;
558 var keyCols = tableInfo.IndexOfColumns(constraint.
ColumnNames).ToArray();
559 var keyEntries = keyTable.FindKeys(keyCols, originalKey).ToList();
562 if (keyEntries.Count > 0) {
567 constraint.
Deferred.AsDebugString() +
568 " foreign key constraint violation on delete (" +
578 foreach (
int rowNum
in keyEntries) {
579 var dataRow =
new Row(keyTable,
new RowId(tableInfo.Id, rowNum));
580 dataRow.SetFromTable();
584 keyTable.RemoveRow(dataRow.RowId);
586 for (
int n = 0; n < keyCols.Length; ++n) {
587 dataRow.SetNull(keyCols[n]);
589 keyTable.UpdateRow(dataRow);
591 for (
int n = 0; n < keyCols.Length; ++n) {
592 dataRow.SetDefault(keyCols[n], context);
594 keyTable.UpdateRow(dataRow);
596 throw new Exception(
"Do not understand referential action: " + deleteRule);
601 keyTable.AssertConstraints();
618 #region RowEnumerator
626 this.enumerator = enumerator;
630 enumerator.Dispose();
634 return enumerator.MoveNext();
642 get {
return new Row(table, enumerator.Current); }
645 object IEnumerator.Current {
646 get {
return Current; }
653 get {
return TableId; }
void Dispose(bool disposing)
bool IsNull
Gets a boolean value indicating if the object equivales to a NULL.
Enumerates a known set of codes in a SQL Model
A database exception that represents a constraint violation.
void EnsureRowIndexListCurrent()
ColumnIndex[] columnIndexes
The system implementation of a transaction model that handles isolated operations within a database c...
readonly TransactionTable table
readonly IIndexEnumerator< int > enumerator
abstract void Insert(int rowNumber)
ConstraintDeferrability Deferred
Describes the name of an object within a database.
ConstraintDeferrability
The type of deferrance of a constraint.
A single row in a table of a database.
void UpdateRow(Row row)
Updates the values of a row into the table.
int RowNumber
Gets the number of the column within the table referenced.
TransactionTable(ITransaction transaction, TableSource tableSource, TableEventRegistry eventRegistry)
IEnumerator< Row > GetEnumerator()
ObjectName TableName
Gets the fully qualified name of the table that is ensured to be unique within the system...
void Rollback()
Rollback any write operations done during the lifetime of this transaction and invalidates it...
ForeignKeyAction
Enumerates the foreign key referential trigger actions.
void ExecuteUpdateReferentialAction(ConstraintInfo constraint, DataObject[] originalKey, DataObject[] newKey, IQuery context)
const int ForeignKeyViolation
A Foreign Key constraint violation error code.
ColumnIndex CreateColumnIndex(IIndexSet indexSet, ITable table, int columnOffset)
DataObject GetValue(int rowIndex, int columnOffset)
IIndex GetIndex(int index)
Gets a mutable implementation of IIndex for the given index number in this set of indices...
void Acquired(Lock @lock)
void FlushIndexes()
Flushes all changes made on this table to the backing index scheme.
Represents a dynamic object that encapsulates a defined SqlType and a compatible constant ISqlObject ...
ForeignKeyAction OnDelete
void Released(Lock @lock)
string FullName
Gets the full reference name formatted.
An object that access to a set of indexes.
An interface for querying and accessing an index of primitive integers.
void ExecuteDeleteReferentialAction(ConstraintInfo constraint, DataObject[] originalKey, IQuery context)
void EnsureColumnIndexCurrent(int column)
RowId AddRow(Row row)
Persists a new row to the table.
string[] ForeignColumnNames
Defines the value of a ROWID object, that is a unique reference within a database system to a single ...
DataObject GetValue(long rowNumber, int columnOffset)
Gets a single cell within the table that is located at the given column offset and row...
ForeignKeyAction OnUpdate
void AssertConstraints()
Performs all constraint integrity checks and actions to any modifications based on any changes that h...
int ColumnCount
Gets a count of the columns defined by this object.
void SetRowNumber(int rowNumber)
Sets the number component of the ID of this column.
IDatabaseContext DatabaseContext
The simplest implementation of a transaction.
DbObjectType
The kind of objects that can be handled by a database system and its managers
ColumnIndex GetIndex(int columnOffset)
Gets an index for given column that can be used to select values from this table. ...
bool RemoveRow(RowId rowId)
Deletes row identified by the given coordinates from the table.
Defines the metadata properties of a table existing within a database.
int TableId
Gets the unique identifier of the table the row is contained.
TableRowEventType
The kind of events that can happen on a table row during the life-time of a transaction.
An interface that defines contracts to alter the contents of a table.
RowEnumerator(TransactionTable table, IIndexEnumerator< int > enumerator)
RowId RowId
Gets the row unique identifier within the database.