Exemplo n.º 1
0
        private ITable[] FindChangedTables(ITransaction checkTransaction, CommitTableInfo[] normalizedChangedTables)
        {
            var changedTableSource = new ITable[normalizedChangedTables.Length];

            // Set up the above arrays
            for (int i = 0; i < normalizedChangedTables.Length; ++i)
            {
                // Get the information for this changed table
                CommitTableInfo tableInfo = normalizedChangedTables[i];

                // Get the master table that changed from the normalized list.
                TableSource master = tableInfo.Master;
                // Did this table change since the transaction started?
                TableEventRegistry[] allTableChanges = tableInfo.ChangesSinceCommit;

                if (allTableChanges == null || allTableChanges.Length == 0)
                {
                    // No changes so we can pick the correct IIndexSet from the current
                    // transaction.

                    // Get the state of the changed tables from the Transaction
                    var mtable = Transaction.GetMutableTable(master.TableName);
                    // Get the current index set of the changed table
                    tableInfo.IndexSet = Transaction.GetIndexSetForTable(master);
                    // Flush all index changes in the table
                    mtable.FlushIndexes();

                    // Set the 'check_transaction' object with the latest version of the
                    // table.
                    checkTransaction.UpdateVisibleTable(tableInfo.Master, tableInfo.IndexSet);
                }
                else
                {
                    // There were changes so we need to merge the changes with the
                    // current view of the table.

                    // It's not immediately obvious how this merge update works, but
                    // basically what happens is we WriteByte the table journal with all the
                    // changes into a new IMutableTableDataSource of the current
                    // committed state, and then we flush all the changes into the
                    // index and then update the 'check_transaction' with this change.

                    // Create the IMutableTableDataSource with the changes from this
                    // journal.
                    var mtable = master.CreateTableAtCommit(checkTransaction, tableInfo.Journal);
                    // Get the current index set of the changed table
                    tableInfo.IndexSet = checkTransaction.GetIndexSetForTable(master);
                    // Flush all index changes in the table
                    mtable.FlushIndexes();

                    // Dispose the table
                    mtable.Dispose();
                }

                // And now refresh the 'changedTableSource' entry
                changedTableSource[i] = checkTransaction.GetTable(master.TableName);
            }

            return(changedTableSource);
        }
Exemplo n.º 2
0
        private void ExecuteDeleteReferentialAction(ConstraintInfo constraint, DataObject[] originalKey, IQuery context)
        {
            var deleteRule = constraint.OnDelete;

            if (deleteRule == ForeignKeyAction.NoAction &&
                constraint.Deferred != ConstraintDeferrability.InitiallyImmediate)
            {
                // Constraint check is deferred
                return;
            }

            // So either delete rule is not NO ACTION, or if it is we are initially
            // immediate.
            var keyTable   = Transaction.GetMutableTable(constraint.TableName);
            var tableInfo  = keyTable.TableInfo;
            var keyCols    = tableInfo.IndexOfColumns(constraint.ColumnNames).ToArray();
            var keyEntries = keyTable.FindKeys(keyCols, originalKey).ToList();

            // Are there keys effected?
            if (keyEntries.Count > 0)
            {
                if (deleteRule == ForeignKeyAction.NoAction)
                {
                    // Throw an exception;
                    throw new ConstraintViolationException(
                              SqlModelErrorCodes.ForeignKeyViolation,
                              constraint.Deferred.AsDebugString() +
                              " foreign key constraint violation on delete (" +
                              constraint.ConstraintName + ") Columns = " +
                              constraint.TableName + "( " +
                              String.Join(", ", constraint.ColumnNames) +
                              " ) -> " + constraint.ForeignTable.FullName + "( " +
                              String.Join(", ", constraint.ForeignColumnNames) +
                              " )");
                }

                // Perform a referential action on each updated key
                foreach (int rowNum in keyEntries)
                {
                    var dataRow = new Row(keyTable, new RowId(tableInfo.Id, rowNum));
                    dataRow.SetFromTable();

                    if (deleteRule == ForeignKeyAction.Cascade)
                    {
                        // Cascade the removal of the referenced rows
                        keyTable.RemoveRow(dataRow.RowId);
                    }
                    else if (deleteRule == ForeignKeyAction.SetNull)
                    {
                        for (int n = 0; n < keyCols.Length; ++n)
                        {
                            dataRow.SetNull(keyCols[n]);
                        }
                        keyTable.UpdateRow(dataRow);
                    }
                    else if (deleteRule == ForeignKeyAction.SetDefault)
                    {
                        for (int n = 0; n < keyCols.Length; ++n)
                        {
                            dataRow.SetDefault(keyCols[n], context);
                        }
                        keyTable.UpdateRow(dataRow);
                    }
                    else
                    {
                        throw new Exception("Do not understand referential action: " + deleteRule);
                    }
                }

                // Check referential integrity of modified table,
                keyTable.AssertConstraints();
            }
        }
Exemplo n.º 3
0
        private void ExecuteUpdateReferentialAction(ConstraintInfo constraint, Field[] originalKey, Field[] newKey,
                                                    IQuery context)
        {
            var updateRule = constraint.OnUpdate;

            if (updateRule == ForeignKeyAction.NoAction &&
                constraint.Deferred != ConstraintDeferrability.InitiallyImmediate)
            {
                // Constraint check is deferred
                return;
            }

            // So either update rule is not NO ACTION, or if it is we are initially
            // immediate.
            var keyTable   = Transaction.GetMutableTable(constraint.TableName);
            var tableInfo  = keyTable.TableInfo;
            var keyCols    = tableInfo.IndexOfColumns(constraint.ColumnNames).ToArray();
            var keyEntries = keyTable.FindKeys(keyCols, originalKey);

            // Are there keys effected?
            if (keyEntries.Any())
            {
                if (updateRule == ForeignKeyAction.NoAction)
                {
                    throw new ForeignKeyViolationException(constraint.TableName, constraint.ConstraintName, constraint.ColumnNames,
                                                           constraint.ForeignTable, constraint.ForeignColumnNames, constraint.Deferred);
                }

                // Perform a referential action on each updated key
                foreach (int rowNum in keyEntries)
                {
                    var dataRow = new Row(keyTable, new RowId(keyTable.TableInfo.Id, rowNum));
                    dataRow.SetFromTable();

                    if (updateRule == ForeignKeyAction.Cascade)
                    {
                        // Update the keys
                        for (int n = 0; n < keyCols.Length; ++n)
                        {
                            dataRow.SetValue(keyCols[n], newKey[n]);
                        }
                        keyTable.UpdateRow(dataRow);
                    }
                    else if (updateRule == ForeignKeyAction.SetNull)
                    {
                        for (int n = 0; n < keyCols.Length; ++n)
                        {
                            dataRow.SetNull(keyCols[n]);
                        }
                        keyTable.UpdateRow(dataRow);
                    }
                    else if (updateRule == ForeignKeyAction.SetDefault)
                    {
                        for (int n = 0; n < keyCols.Length; ++n)
                        {
                            dataRow.SetDefault(keyCols[n], context);
                        }
                        keyTable.UpdateRow(dataRow);
                    }
                    else
                    {
                        throw new Exception("Do not understand referential action: " + updateRule);
                    }
                }

                // Check referential integrity of modified table,
                keyTable.AssertConstraints();
            }
        }