예제 #1
0
        private ITable FindViewEntry(ObjectName viewName)
        {
            var table = Transaction.GetTable(SystemSchema.ViewTableName);

            var schemav = table.GetResolvedColumnName(0);
            var namev = table.GetResolvedColumnName(1);

            using (var context = new SystemQueryContext(Transaction, SystemSchema.Name)) {
                var t = table.SimpleSelect(context, namev, SqlExpressionType.Equal, SqlExpression.Constant(DataObject.String(viewName.Name)));
                t = t.ExhaustiveSelect(context, 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;
            }
        }
예제 #2
0
        private ITable FindEntry(Table table, ObjectName routineName)
        {
            var schemav = table.GetResolvedColumnName(0);
            var namev = table.GetResolvedColumnName(1);

            using (var context = new SystemQueryContext(transaction, transaction.CurrentSchema())) {
                var t = table.SimpleSelect(context, namev, SqlExpressionType.Equal,
                    SqlExpression.Constant(DataObject.String(routineName.Name)));
                t = t.ExhaustiveSelect(context,
                    SqlExpression.Equal(SqlExpression.Reference(schemav),
                        SqlExpression.Constant(DataObject.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 static void CheckAddConstraintViolations(this ITransaction transaction, ITable table, int[] rowIndices, ConstraintDeferrability deferred)
        {
            string curSchema = table.TableInfo.TableName.Parent.Name;
            IQueryContext queryContext = new SystemQueryContext(transaction, curSchema);

            // 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 ConstraintViolationException(
                          SqlModelErrorCodes.PrimaryKeyViolation,
                          deferred.AsDebugString() + " primary Key constraint violation (" +
                          primaryKey.ConstraintName + ") Columns = ( " +
                          String.Join(", ", primaryKey.ColumnNames) +
                          " ) Table = ( " + tableName + " )");
                    }
                } // 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 ConstraintViolationException(
                              SqlModelErrorCodes.UniqueViolation,
                              deferred.AsDebugString() + " unique constraint violation (" +
                              unique.ConstraintName + ") Columns = ( " +
                              String.Join(", ", unique.ColumnNames) + " ) Table = ( " +
                              tableName + " )");
                        }
                    } // 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 ConstraintViolationException(
                              SqlModelErrorCodes.ForeignKeyViolation,
                              deferred.AsDebugString() + " foreign key constraint violation (" +
                              reference.ConstraintName + ") Columns = " +
                              reference.TableName + "( " +
                              String.Join(", ", reference.ColumnNames) + " ) -> " +
                              reference.ForeignTable + "( " +
                              String.Join(", ", reference.ForeignColumnNames) + " )");
                        }
                    } // 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) {

                    // TODO: var exp = tableInfo.ResolveColumns(transaction.IgnoreIdentifierCase(), check.CheckExpression);
                    var exp = tableInfo.ResolveColumns(true, 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 (b) {
                                // Evaluated to false so don't allow this row to be added.
                                throw new ConstraintViolationException(
                                   SqlModelErrorCodes.CheckViolation,
                                   deferred.AsDebugString() + " check constraint violation (" +
                                   check.ConstraintName + ") - '" + exp +
                                   "' evaluated to false for inserted/updated row.");
                            }
                        } else {
                            // NOTE: This error will pass the row by default
                            // TODO: emit a warning
                        }
                    }
                }
            }
        }
예제 #4
0
        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;
            var context = new SystemQueryContext(Transaction, currentSchema);

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