private ITable FindViewEntry(ObjectName viewName) { var table = Transaction.GetTable(SystemSchema.ViewTableName); var schemav = table.GetResolvedColumnName(0); var namev = table.GetResolvedColumnName(1); using (var session = new SystemSession(Transaction, SystemSchema.Name)) { using (var query = session.CreateQuery()) { var t = table.SimpleSelect(query, namev, SqlExpressionType.Equal, SqlExpression.Constant(DataObject.String(viewName.Name))); t = t.ExhaustiveSelect(query, SqlExpression.Equal(SqlExpression.Reference(schemav), SqlExpression.Constant(viewName.ParentName))); // This should be at most 1 row in size if (t.RowCount > 1) { throw new ArgumentException(String.Format("Multiple view entries for name '{0}' in the system.", viewName)); } // Return the entries found. return(t); } } }
private ITable FindEntry(ObjectName routineName) { var table = transaction.GetTable(RoutineTableName); var schemav = table.GetResolvedColumnName(1); var namev = table.GetResolvedColumnName(2); using (var session = new SystemSession(transaction)) { using (var context = session.CreateQuery()) { var t = table.SimpleSelect(context, namev, SqlExpressionType.Equal, SqlExpression.Constant(Field.String(routineName.Name))); t = t.ExhaustiveSelect(context, SqlExpression.Equal(SqlExpression.Reference(schemav), SqlExpression.Constant(Field.String(routineName.ParentName)))); // This should be at most 1 row in size if (t.RowCount > 1) { throw new Exception("Assert failed: multiple procedure names for " + routineName); } // Return the entries found. return(t); } } }
public bool DropTrigger(ObjectName triggerName) { if (triggerName == null) { throw new ArgumentNullException("triggerName"); } var table = transaction.GetMutableTable(TriggerTableName); var schemaName = triggerName.ParentName; var name = triggerName.Name; var schemaCol = table.GetResolvedColumnName(0); var nameCol = table.GetResolvedColumnName(1); using (var session = new SystemSession(transaction)) { using (var query = session.CreateQuery()) { var t = table.SimpleSelect(query, nameCol, SqlExpressionType.Equal, SqlExpression.Constant(name)); t = t.ExhaustiveSelect(query, SqlExpression.Equal(SqlExpression.Reference(schemaCol), SqlExpression.Constant(schemaName))); if (t.RowCount == 0) { return(false); } table.Delete(t); transaction.OnObjectDropped(DbObjectType.Trigger, triggerName); return(true); } } }
public View GetView(ObjectName viewName) { var viewTable = Transaction.GetTable(SystemSchema.ViewTableName); var e = viewTable.GetEnumerator(); while (e.MoveNext()) { int row = e.Current.RowId.RowNumber; var cSchema = viewTable.GetValue(row, 0).Value.ToString(); var cName = viewTable.GetValue(row, 1).Value.ToString(); if (viewName.ParentName.Equals(cSchema) && viewName.Name.Equals(cName)) { ViewInfo viewInfo; if (!viewCache.TryGetValue(row, out viewInfo)) { var blob = (SqlBinary)viewTable.GetValue(row, 3).Value; using (var session = new SystemSession(Transaction, SystemSchema.Name)) { using (var context = session.CreateQuery()) { viewInfo = ViewInfo.Deserialize(blob.GetInput()); } } viewCache[row] = viewInfo; } return(new View(viewInfo)); } } return(null); }
public bool TypeExists(ObjectName typeName) { if (typesCache.ContainsKey(typeName)) { return(true); } var table = Transaction.GetTable(TypeTableName); var schemaName = typeName.ParentName; var name = typeName.Name; var schemaCol = table.GetResolvedColumnName(1); var nameCol = table.GetResolvedColumnName(2); using (var session = new SystemSession(Transaction)) { using (var query = session.CreateQuery()) { var t = table.SimpleSelect(query, schemaCol, SqlExpressionType.Equal, SqlExpression.Constant(schemaName)); t = t.ExhaustiveSelect(query, SqlExpression.Equal(SqlExpression.Reference(nameCol), SqlExpression.Constant(name))); if (t.RowCount > 1) { throw new InvalidOperationException(String.Format("Name '{0}' resolves to multiple types.", typeName)); } return(t.RowCount == 1); } } }
private ITable FindTrigger(ITable table, string schema, string name) { // Find all the trigger entries with this name var schemaColumn = table.GetResolvedColumnName(0); var nameColumn = table.GetResolvedColumnName(1); using (var session = new SystemSession(transaction, SystemSchema.Name)) { using (var context = session.CreateQuery()) { var t = table.SimpleSelect(context, nameColumn, SqlExpressionType.Equal, SqlExpression.Constant(DataObject.String(name))); return(t.ExhaustiveSelect(context, SqlExpression.Equal(SqlExpression.Reference(schemaColumn), SqlExpression.Constant(DataObject.String(schema))))); } } }
private IEnumerable <TriggerInfo> FindTriggers(ObjectName tableName, TriggerEventType eventType) { var fullTableName = tableName.FullName; var eventTypeCode = (int)eventType; var table = transaction.GetTable(SystemSchema.TriggerTableName); if (table == null) { return(new TriggerInfo[0]); } var tableColumn = table.GetResolvedColumnName(3); var eventTypeColumn = table.GetResolvedColumnName(4); ITable result; using (var session = new SystemSession(transaction, SystemSchema.Name)) { using (var context = session.CreateQuery()) { var t = table.SimpleSelect(context, tableColumn, SqlExpressionType.Equal, SqlExpression.Constant(DataObject.String(fullTableName))); result = t.ExhaustiveSelect(context, SqlExpression.Equal(SqlExpression.Reference(eventTypeColumn), SqlExpression.Constant(eventTypeCode))); } } if (result.RowCount == 0) { return(new TriggerInfo[0]); } var list = new List <TriggerInfo>(); foreach (var row in result) { var triggerInfo = FormTrigger(row); //TODO: get the other information such has the body, the external method or the procedure // if this is a non-callback list.Add(triggerInfo); } return(list.AsEnumerable()); }
private View GetViewAt(int offset) { var table = Transaction.GetTable(SystemSchema.ViewTableName); if (table == null) { throw new DatabaseSystemException(String.Format("System table '{0}' was not defined.", SystemSchema.ViewTableName)); } var e = table.GetEnumerator(); int i = 0; while (e.MoveNext()) { var row = e.Current.RowId.RowNumber; if (i == offset) { ViewInfo viewInfo; if (!viewCache.TryGetValue(row, out viewInfo)) { var binary = (ISqlBinary)table.GetValue(row, 3).Value; using (var session = new SystemSession(Transaction, SystemSchema.Name)) { using (var context = session.CreateQuery()) { viewInfo = ViewInfo.Deserialize(binary.GetInput()); } } viewCache[row] = viewInfo; } return(new View(viewInfo)); } ++i; } throw new ArgumentOutOfRangeException("offset"); }
public bool RoutineExists(ObjectName routineName) { if (routinesCache.ContainsKey(routineName)) { return(true); } var table = transaction.GetTable(RoutineTableName); var schemav = table.GetResolvedColumnName(1); var namev = table.GetResolvedColumnName(2); using (var session = new SystemSession(transaction)) { using (var context = session.CreateQuery()) { var t = table.SimpleSelect(context, namev, SqlExpressionType.Equal, SqlExpression.Constant(Field.String(routineName.Name))); t = t.ExhaustiveSelect(context, SqlExpression.Equal(SqlExpression.Reference(schemav), SqlExpression.Constant(Field.String(routineName.ParentName)))); return(t.RowCount == 1); } } }
public View GetView(ObjectName viewName) { var viewTable = Transaction.GetTable(SystemSchema.ViewTableName); var e = viewTable.GetEnumerator(); while (e.MoveNext()) { int row = e.Current.RowId.RowNumber; var cSchema = viewTable.GetValue(row, 0).Value.ToString(); var cName = viewTable.GetValue(row, 1).Value.ToString(); if (viewName.ParentName.Equals(cSchema) && viewName.Name.Equals(cName)) { ViewInfo viewInfo; if (!viewCache.TryGetValue(row, out viewInfo)) { var blob = (SqlBinary)viewTable.GetValue(row, 3).Value; using (var session = new SystemSession(Transaction, SystemSchema.Name)) { using (var context = session.CreateQuery()) { viewInfo = ViewInfo.Deserialize(blob.GetInput()); } } viewCache[row] = viewInfo; } return new View(viewInfo); } } return null; }
public bool TypeExists(ObjectName typeName) { if (typesCache.ContainsKey(typeName)) return true; var table = Transaction.GetTable(TypeTableName); var schemaName = typeName.ParentName; var name = typeName.Name; var schemaCol = table.GetResolvedColumnName(1); var nameCol = table.GetResolvedColumnName(2); using (var session = new SystemSession(Transaction)) { using (var query = session.CreateQuery()) { var t = table.SimpleSelect(query, schemaCol, SqlExpressionType.Equal, SqlExpression.Constant(schemaName)); t = t.ExhaustiveSelect(query, SqlExpression.Equal(SqlExpression.Reference(nameCol), SqlExpression.Constant(name))); if (t.RowCount > 1) throw new InvalidOperationException(String.Format("Name '{0}' resolves to multiple types.", typeName)); return t.RowCount == 1; } } }
public UserType GetUserType(ObjectName typeName) { UserType userType; if (!typesCache.TryGetValue(typeName, out userType)) { var typeTable = Transaction.GetTable(TypeTableName); var membersTable = Transaction.GetTable(TypeMemberTableName); var schemaName = typeName.ParentName; var name = typeName.Name; var schemaColumn = typeTable.GetResolvedColumnName(1); var nameColumn = typeTable.GetResolvedColumnName(2); var idColumn = membersTable.GetResolvedColumnName(0); UserTypeInfo typeInfo; using (var session = new SystemSession(Transaction)) { using (var query = session.CreateQuery()) { var t = typeTable.SimpleSelect(query, schemaColumn, SqlExpressionType.Equal, SqlExpression.Constant(schemaName)); t = t.ExhaustiveSelect(query, SqlExpression.Equal(SqlExpression.Reference(nameColumn), SqlExpression.Constant(name))); if (t.RowCount == 0) return null; var id = t.GetValue(0, 0); var parentField = t.GetValue(0, 3); ObjectName parentType = null; if (!Field.IsNullField(parentField)) { parentType = ObjectName.Parse(parentField.Value.ToString()); } typeInfo = new UserTypeInfo(typeName, parentType); var isSealedField = t.GetValue(0, 4); var isAbstractField = t.GetValue(0, 5); if (!Field.IsNullField(isSealedField)) { typeInfo.IsSealed = (SqlBoolean) isSealedField.AsBoolean().Value; } if (!Field.IsNullField(isAbstractField)) { typeInfo.IsAbstract = (SqlBoolean) isAbstractField.AsBoolean().Value; } var owner = t.GetValue(0, 6).Value.ToString(); typeInfo.Owner = owner; var t2 = membersTable.SimpleSelect(query, idColumn, SqlExpressionType.Equal, SqlExpression.Constant(id)); foreach (var row in t2) { var memberName = row.GetValue(1).Value.ToString(); var memberTypeString = row.GetValue(2).Value.ToString(); var memberType = SqlType.Parse(Transaction.Context, memberTypeString); if (memberType == null) throw new InvalidOperationException(String.Format("Cannot find the type '{0}' for member '{1}' of type '{2}'.", memberTypeString, memberName, typeName)); typeInfo.AddMember(memberName, memberType); } } } userType = new UserType(typeInfo); typesCache[typeName] = userType; } return userType; }
private ITable FindEntry(ObjectName routineName) { var table = transaction.GetTable(RoutineTableName); var schemav = table.GetResolvedColumnName(1); var namev = table.GetResolvedColumnName(2); using (var session = new SystemSession(transaction)) { using (var context = session.CreateQuery()) { var t = table.SimpleSelect(context, namev, SqlExpressionType.Equal, SqlExpression.Constant(Field.String(routineName.Name))); t = t.ExhaustiveSelect(context, SqlExpression.Equal(SqlExpression.Reference(schemav), SqlExpression.Constant(Field.String(routineName.ParentName)))); // This should be at most 1 row in size if (t.RowCount > 1) throw new Exception("Assert failed: multiple procedure names for " + routineName); // Return the entries found. return t; } } }
public bool RoutineExists(ObjectName routineName) { if (routinesCache.ContainsKey(routineName)) return true; var table = transaction.GetTable(RoutineTableName); var schemav = table.GetResolvedColumnName(1); var namev = table.GetResolvedColumnName(2); using (var session = new SystemSession(transaction)) { using (var context = session.CreateQuery()) { var t = table.SimpleSelect(context, namev, SqlExpressionType.Equal, SqlExpression.Constant(Field.String(routineName.Name))); t = t.ExhaustiveSelect(context, SqlExpression.Equal(SqlExpression.Reference(schemav), SqlExpression.Constant(Field.String(routineName.ParentName)))); return t.RowCount == 1; } } }
public bool AlterTable(TableInfo tableInfo) { tableInfo = tableInfo.AsReadOnly(); var tableName = tableInfo.TableName; // The current schema context is the schema of the table name string currentSchema = tableName.Parent.Name; using (var session = new SystemSession(Transaction, currentSchema)) { using (var context = session.CreateQuery()) { // Get the next unique id of the unaltered table. var nextId = NextUniqueId(tableName); // Drop the current table var cTable = GetTable(tableName); var droppedTableId = cTable.TableInfo.Id; DropTable(tableName); // And create the table CreateTable(tableInfo); var alteredTable = GetMutableTable(tableName); ITableSource source; if (!visibleTables.TryGet(tableName, out source)) { throw new InvalidOperationException(); } int alteredTableId = source.TableId; // Set the sequence id of the table source.SetUniqueId(nextId.ToInt64()); // Work out which columns we have to copy to where int[] colMap = new int[tableInfo.ColumnCount]; var origTd = cTable.TableInfo; for (int i = 0; i < colMap.Length; ++i) { string colName = tableInfo[i].ColumnName; colMap[i] = origTd.IndexOfColumn(colName); } // First move all the rows from the old table to the new table, // This does NOT update the indexes. var e = cTable.GetEnumerator(); while (e.MoveNext()) { int rowIndex = e.Current.RowId.RowNumber; var dataRow = alteredTable.NewRow(); for (int i = 0; i < colMap.Length; ++i) { int col = colMap[i]; if (col != -1) { dataRow.SetValue(i, cTable.GetValue(rowIndex, col)); } } dataRow.SetDefault(context); // Note we use a low level 'AddRow' method on the master table // here. This does not touch the table indexes. The indexes are // built later. int newRowNumber = source.AddRow(dataRow); // Set the record as committed added source.WriteRecordState(newRowNumber, RecordState.CommittedAdded); } // TODO: We need to copy any existing index definitions that might // have been set on the table being altered. // Rebuild the indexes in the new master table, source.BuildIndexes(); // Get the snapshot index set on the new table and set it here SetIndexSetForTable(source, source.CreateIndexSet()); // Flush this out of the table cache FlushTableCache(tableName); // Ensure the native sequence generator exists... Transaction.RemoveNativeSequence(tableName); Transaction.CreateNativeSequence(tableName); // Notify that this database object has been successfully dropped and // created. Transaction.OnTableDropped(droppedTableId, tableName); Transaction.OnTableCreated(alteredTableId, tableName); return(true); } } }
public bool DropTrigger(ObjectName triggerName) { if (triggerName == null) throw new ArgumentNullException("triggerName"); var table = transaction.GetMutableTable(TriggerTableName); var schemaName = triggerName.ParentName; var name = triggerName.Name; var schemaCol = table.GetResolvedColumnName(0); var nameCol = table.GetResolvedColumnName(1); using (var session = new SystemSession(transaction)) { using (var query = session.CreateQuery()) { var t = table.SimpleSelect(query, nameCol, SqlExpressionType.Equal, SqlExpression.Constant(name)); t = t.ExhaustiveSelect(query, SqlExpression.Equal(SqlExpression.Reference(schemaCol), SqlExpression.Constant(schemaName))); if (t.RowCount == 0) return false; table.Delete(t); transaction.OnObjectDropped(DbObjectType.Trigger, triggerName); return true; } } }
private ITable FindViewEntry(ObjectName viewName) { var table = Transaction.GetTable(SystemSchema.ViewTableName); var schemav = table.GetResolvedColumnName(0); var namev = table.GetResolvedColumnName(1); using (var session = new SystemSession(Transaction, SystemSchema.Name)) { using (var query =session.CreateQuery()) { var t = table.SimpleSelect(query, namev, SqlExpressionType.Equal, SqlExpression.Constant(DataObject.String(viewName.Name))); t = t.ExhaustiveSelect(query, SqlExpression.Equal(SqlExpression.Reference(schemav), SqlExpression.Constant(viewName.ParentName))); // This should be at most 1 row in size if (t.RowCount > 1) throw new ArgumentException(String.Format("Multiple view entries for name '{0}' in the system.", viewName)); // Return the entries found. return t; } } }
public UserType GetUserType(ObjectName typeName) { UserType userType; if (!typesCache.TryGetValue(typeName, out userType)) { var typeTable = Transaction.GetTable(TypeTableName); var membersTable = Transaction.GetTable(TypeMemberTableName); var schemaName = typeName.ParentName; var name = typeName.Name; var schemaColumn = typeTable.GetResolvedColumnName(1); var nameColumn = typeTable.GetResolvedColumnName(2); var idColumn = membersTable.GetResolvedColumnName(0); UserTypeInfo typeInfo; using (var session = new SystemSession(Transaction)) { using (var query = session.CreateQuery()) { var t = typeTable.SimpleSelect(query, schemaColumn, SqlExpressionType.Equal, SqlExpression.Constant(schemaName)); t = t.ExhaustiveSelect(query, SqlExpression.Equal(SqlExpression.Reference(nameColumn), SqlExpression.Constant(name))); if (t.RowCount == 0) { return(null); } var id = t.GetValue(0, 0); var parentField = t.GetValue(0, 3); ObjectName parentType = null; if (!Field.IsNullField(parentField)) { parentType = ObjectName.Parse(parentField.Value.ToString()); } typeInfo = new UserTypeInfo(typeName, parentType); var isSealedField = t.GetValue(0, 4); var isAbstractField = t.GetValue(0, 5); if (!Field.IsNullField(isSealedField)) { typeInfo.IsSealed = (SqlBoolean)isSealedField.AsBoolean().Value; } if (!Field.IsNullField(isAbstractField)) { typeInfo.IsAbstract = (SqlBoolean)isAbstractField.AsBoolean().Value; } var owner = t.GetValue(0, 6).Value.ToString(); typeInfo.Owner = owner; var t2 = membersTable.SimpleSelect(query, idColumn, SqlExpressionType.Equal, SqlExpression.Constant(id)); foreach (var row in t2) { var memberName = row.GetValue(1).Value.ToString(); var memberTypeString = row.GetValue(2).Value.ToString(); var memberType = SqlType.Parse(Transaction.Context, memberTypeString); if (memberType == null) { throw new InvalidOperationException(String.Format("Cannot find the type '{0}' for member '{1}' of type '{2}'.", memberTypeString, memberName, typeName)); } typeInfo.AddMember(memberName, memberType); } } } userType = new UserType(typeInfo); typesCache[typeName] = userType; } return(userType); }
private View GetViewAt(int offset) { var table = Transaction.GetTable(SystemSchema.ViewTableName); if (table == null) throw new DatabaseSystemException(String.Format("System table '{0}' was not defined.", SystemSchema.ViewTableName)); var e = table.GetEnumerator(); int i = 0; while (e.MoveNext()) { var row = e.Current.RowId.RowNumber; if (i == offset) { ViewInfo viewInfo; if (!viewCache.TryGetValue(row, out viewInfo)) { var binary = (ISqlBinary)table.GetValue(row, 3).Value; using (var session = new SystemSession(Transaction, SystemSchema.Name)) { using (var context = session.CreateQuery()) { viewInfo = ViewInfo.Deserialize(binary.GetInput()); } } viewCache[row] = viewInfo; } return new View(viewInfo); } ++i; } throw new ArgumentOutOfRangeException("offset"); }
public bool AlterTable(TableInfo tableInfo) { tableInfo = tableInfo.AsReadOnly(); var tableName = tableInfo.TableName; // The current schema context is the schema of the table name string currentSchema = tableName.Parent.Name; using (var session = new SystemSession(Transaction, currentSchema)) { using (var context = session.CreateQuery()) { // Get the next unique id of the unaltered table. var nextId = NextUniqueId(tableName); // Drop the current table var cTable = GetTable(tableName); var droppedTableId = cTable.TableInfo.Id; DropTable(tableName); // And create the table table CreateTable(tableInfo); var alteredTable = GetMutableTable(tableName); var source = FindVisibleTable(tableName, false); int alteredTableId = source.TableId; // Set the sequence id of the table source.SetUniqueId(nextId.ToInt64()); // Work out which columns we have to copy to where int[] colMap = new int[tableInfo.ColumnCount]; var origTd = cTable.TableInfo; for (int i = 0; i < colMap.Length; ++i) { string colName = tableInfo[i].ColumnName; colMap[i] = origTd.IndexOfColumn(colName); } // First move all the rows from the old table to the new table, // This does NOT update the indexes. var e = cTable.GetEnumerator(); while (e.MoveNext()) { int rowIndex = e.Current.RowId.RowNumber; var dataRow = alteredTable.NewRow(); for (int i = 0; i < colMap.Length; ++i) { int col = colMap[i]; if (col != -1) { dataRow.SetValue(i, cTable.GetValue(rowIndex, col)); } } dataRow.SetDefault(context); // Note we use a low level 'AddRow' method on the master table // here. This does not touch the table indexes. The indexes are // built later. int newRowNumber = source.AddRow(dataRow); // Set the record as committed added source.WriteRecordState(newRowNumber, RecordState.CommittedAdded); } // TODO: We need to copy any existing index definitions that might // have been set on the table being altered. // Rebuild the indexes in the new master table, source.BuildIndexes(); // Get the snapshot index set on the new table and set it here SetIndexSetForTable(source, source.CreateIndexSet()); // Flush this out of the table cache FlushTableCache(tableName); // Ensure the native sequence generator exists... Transaction.RemoveNativeSequence(tableName); Transaction.CreateNativeSequence(tableName); // Notify that this database object has been successfully dropped and // created. Transaction.Registry.RegisterEvent(new TableDroppedEvent(droppedTableId, tableName)); Transaction.Registry.RegisterEvent(new TableCreatedEvent(alteredTableId, tableName)); return true; } } }
private IEnumerable<TriggerInfo> FindTriggers(ObjectName tableName, TriggerEventType eventType) { var fullTableName = tableName.FullName; var eventTypeCode = (int)eventType; var table = transaction.GetTable(SystemSchema.TriggerTableName); if (table == null) return new TriggerInfo[0]; var tableColumn = table.GetResolvedColumnName(3); var eventTypeColumn = table.GetResolvedColumnName(4); ITable result; using (var session = new SystemSession(transaction, SystemSchema.Name)) { using (var context = session.CreateQuery()) { var t = table.SimpleSelect(context, tableColumn, SqlExpressionType.Equal, SqlExpression.Constant(DataObject.String(fullTableName))); result = t.ExhaustiveSelect(context, SqlExpression.Equal(SqlExpression.Reference(eventTypeColumn), SqlExpression.Constant(eventTypeCode))); } } if (result.RowCount == 0) return new TriggerInfo[0]; var list = new List<TriggerInfo>(); foreach (var row in result) { var triggerInfo = FormTrigger(row); //TODO: get the other information such has the body, the external method or the procedure // if this is a non-callback list.Add(triggerInfo); } return list.AsEnumerable(); }
public void AssertConstraints() { AssertNotDisposed(); try { // Early exit condition if (lastEntryRICheck == EventRegistry.EventCount) { return; } // This table name var tableInfo = TableInfo; var tName = tableInfo.TableName; using (var session = new SystemSession(Transaction, tName.ParentName)) { using (var context = session.CreateQuery()) { // Are there any added, deleted or updated entries in the journal since // we last checked? List <int> rowsUpdated = new List <int>(); List <int> rowsDeleted = new List <int>(); List <int> rowsAdded = new List <int>(); var events = EventRegistry.Skip(lastEntryRICheck); foreach (var tableEvent in events.OfType <TableRowEvent>()) { var rowNum = tableEvent.RowNumber; if (tableEvent.EventType == TableRowEventType.Remove || tableEvent.EventType == TableRowEventType.UpdateRemove) { rowsDeleted.Add(rowNum); var index = rowsAdded.IndexOf(rowNum); if (index != -1) { rowsAdded.RemoveAt(index); } } else if (tableEvent.EventType == TableRowEventType.Add || tableEvent.EventType == TableRowEventType.UpdateAdd) { rowsAdded.Add(rowNum); } if (tableEvent.EventType == TableRowEventType.UpdateAdd || tableEvent.EventType == TableRowEventType.UpdateRemove) { rowsUpdated.Add(rowNum); } } // Were there any updates or deletes? if (rowsDeleted.Count > 0) { // Get all references on this table var foreignConstraints = Transaction.QueryTableImportedForeignKeys(tName); // For each foreign constraint foreach (var constraint in foreignConstraints) { // For each deleted/updated record in the table, foreach (var rowNum in rowsDeleted) { // What was the key before it was updated/deleted var cols = tableInfo.IndexOfColumns(constraint.ForeignColumnNames).ToArray(); var originalKey = new DataObject[cols.Length]; int nullCount = 0; for (int p = 0; p < cols.Length; ++p) { originalKey[p] = GetValue(rowNum, cols[p]); if (originalKey[p].IsNull) { ++nullCount; } } // Check the original key isn't null if (nullCount != cols.Length) { // Is is an update? int updateIndex = rowsUpdated.IndexOf(rowNum); if (updateIndex != -1) { // Yes, this is an update int rowIndexAdd = rowsUpdated[updateIndex + 1]; // It must be an update, so first see if the change caused any // of the keys to change. bool keyChanged = false; var keyUpdatedTo = new DataObject[cols.Length]; for (int p = 0; p < cols.Length; ++p) { keyUpdatedTo[p] = GetValue(rowIndexAdd, cols[p]); if (originalKey[p].CompareTo(keyUpdatedTo[p]) != 0) { keyChanged = true; } } if (keyChanged) { // Allow the delete, and execute the action, // What did the key update to? ExecuteUpdateReferentialAction(constraint, originalKey, keyUpdatedTo, context); } // If the key didn't change, we don't need to do anything. } else { // No, so it must be a delete, // This will look at the referencee table and if it contains // the key, work out what to do with it. ExecuteDeleteReferentialAction(constraint, originalKey, context); } } // If the key isn't null } // for each deleted rows } // for each foreign key reference to this table } // Were there any rows added (that weren't deleted)? if (rowsAdded.Count > 0) { int[] rowIndices = rowsAdded.ToArray(); // Check for any field constraint violations in the added rows Transaction.CheckFieldConstraintViolations(this, rowIndices); // Check this table, adding the given row_index, immediate Transaction.CheckAddConstraintViolations(this, rowIndices, ConstraintDeferrability.InitiallyImmediate); } } } } catch (ConstraintViolationException) { // If a constraint violation, roll back the changes since the last // check. int rollbackPoint = EventRegistry.EventCount - lastEntryRICheck; if (rowListRebuild <= rollbackPoint) { EventRegistry.Rollback(rollbackPoint); } else { // TODO: emit a warning } throw; } finally { // Make sure we update the 'last_entry_ri_check' variable lastEntryRICheck = EventRegistry.EventCount; } }
private ITable FindTrigger(ITable table, string schema, string name) { // Find all the trigger entries with this name var schemaColumn = table.GetResolvedColumnName(0); var nameColumn = table.GetResolvedColumnName(1); using (var session = new SystemSession(transaction, SystemSchema.Name)) { using (var context = session.CreateQuery()) { var t = table.SimpleSelect(context, nameColumn, SqlExpressionType.Equal, SqlExpression.Constant(Field.String(name))); return t.ExhaustiveSelect(context, SqlExpression.Equal(SqlExpression.Reference(schemaColumn), SqlExpression.Constant(Field.String(schema)))); } } }
public static void CheckAddConstraintViolations(this ITransaction transaction, ITable table, int[] rowIndices, ConstraintDeferrability deferred) { string curSchema = table.TableInfo.TableName.Parent.Name; using (var session = new SystemSession(transaction, curSchema)) { using (var queryContext = session.CreateQuery()) { // Quick exit case if (rowIndices == null || rowIndices.Length == 0) { return; } var tableInfo = table.TableInfo; var tableName = tableInfo.TableName; // ---- Constraint checking ---- // Check any primary key constraint. var primaryKey = transaction.QueryTablePrimaryKey(tableName); if (primaryKey != null && (deferred == ConstraintDeferrability.InitiallyDeferred || primaryKey.Deferred == ConstraintDeferrability.InitiallyImmediate)) { // For each row added to this column foreach (int rowIndex in rowIndices) { if (!IsUniqueColumns(table, rowIndex, primaryKey.ColumnNames, false)) { throw new PrimaryKeyViolationException(tableName, primaryKey.ConstraintName, primaryKey.ColumnNames, deferred); } } // For each row being added } // Check any unique constraints. var uniqueConstraints = transaction.QueryTableUniqueKeys(tableName); foreach (var unique in uniqueConstraints) { if (deferred == ConstraintDeferrability.InitiallyDeferred || unique.Deferred == ConstraintDeferrability.InitiallyImmediate) { // For each row added to this column foreach (int rowIndex in rowIndices) { if (!IsUniqueColumns(table, rowIndex, unique.ColumnNames, true)) { throw new UniqueKeyViolationException(tableName, unique.ConstraintName, unique.ColumnNames, deferred); } } // For each row being added } } // Check any foreign key constraints. // This ensures all foreign references in the table are referenced // to valid records. var foreignConstraints = transaction.QueryTableForeignKeys(tableName); foreach (var reference in foreignConstraints) { if (deferred == ConstraintDeferrability.InitiallyDeferred || reference.Deferred == ConstraintDeferrability.InitiallyImmediate) { // For each row added to this column foreach (int rowIndex in rowIndices) { // Make sure the referenced record exists // Return the count of records where the given row of // table_name(columns, ...) IN // ref_table_name(ref_columns, ...) int rowCount = RowCountOfReferenceTable(transaction, rowIndex, reference.TableName, reference.ColumnNames, reference.ForeignTable, reference.ForeignColumnNames, false); if (rowCount == -1) { // foreign key is NULL } if (rowCount == 0) { throw new ForeignKeyViolationException(tableName, reference.ConstraintName, reference.ColumnNames, reference.ForeignTable, reference.ForeignColumnNames, deferred); } } // For each row being added. } } // Any general checks of the inserted data var checkConstraints = transaction.QueryTableCheckExpressions(tableName); // For each check constraint, check that it evaluates to true. for (int i = 0; i < checkConstraints.Length; ++i) { var check = checkConstraints[i]; if (deferred == ConstraintDeferrability.InitiallyDeferred || check.Deferred == ConstraintDeferrability.InitiallyImmediate) { var exp = tableInfo.ResolveColumns(transaction.IgnoreIdentifiersCase(), check.CheckExpression); // For each row being added to this column for (int rn = 0; rn < rowIndices.Length; ++rn) { var resolver = new TableRowVariableResolver(table, rowIndices[rn]); var evalExp = exp.Evaluate(queryContext, resolver, null); var ob = ((SqlConstantExpression)evalExp).Value; var b = ob.AsBoolean(); if (!b.IsNull) { if (!((SqlBoolean)b.Value)) { // Evaluated to false so don't allow this row to be added. throw new CheckViolationException(tableName, check.ConstraintName, check.CheckExpression, deferred); } } else { // NOTE: This error will pass the row by default // TODO: emit a warning } } } } } } }