コード例 #1
0
        /// <summary>
        /// Creates a single column with the specified definition in the table
        /// underlying this table definition
        /// </summary>
        /// <param name="columnDefinition">The column definition.</param>
        /// <returns>The <see cref="Columnid"/> object corresponding to the
        /// newly-added column.</returns>
        /// <remarks>
        /// It is currently not possible to add an AutoIncrement column to a
        /// table that is being used by a Cursor.  All such Cursors must be
        /// disposed before the column can be successfully added.
        /// </remarks>
        public Columnid AddColumn(ColumnDefinition columnDefinition)
        {
            lock (this.database.IsamSession)
            {
                using (IsamTransaction trx = new IsamTransaction(this.database.IsamSession))
                {
                    OpenTableGrbit grbit = OpenTableGrbit.None;

                    // if we are trying to add an auto-inc column then we must
                    // be able to open the table for exclusive access.  if we can't
                    // then we will not be able to add the column
                    if ((columnDefinition.Flags & ColumnFlags.AutoIncrement) != 0)
                    {
                        grbit = grbit | OpenTableGrbit.DenyRead;
                    }

                    // open the table with the appropriate access
                    JET_TABLEID tableid;
                    Api.JetOpenTable(this.database.IsamSession.Sesid, this.database.Dbid, this.name, null, 0, grbit, out tableid);

                    // add the new column to the table
                    JET_COLUMNDEF columndef = new JET_COLUMNDEF();
                    columndef.coltyp = DatabaseCommon.ColtypFromColumnDefinition(columnDefinition);
                    columndef.cp     = JET_CP.Unicode;
                    columndef.cbMax  = columnDefinition.MaxLength;
                    columndef.grbit  = Converter.ColumndefGrbitFromColumnFlags(columnDefinition.Flags);
                    byte[] defaultValueBytes = Converter.BytesFromObject(
                        columndef.coltyp,
                        false /* ASCII */,
                        columnDefinition.DefaultValue);
                    int          defaultValueBytesLength = (defaultValueBytes == null) ? 0 : defaultValueBytes.Length;
                    JET_COLUMNID jetColumnid;
                    Api.JetAddColumn(
                        this.database.IsamSession.Sesid,
                        tableid,
                        columnDefinition.Name,
                        columndef,
                        defaultValueBytes,
                        defaultValueBytesLength,
                        out jetColumnid);

                    // commit our change
                    Api.JetCloseTable(this.database.IsamSession.Sesid, tableid);
                    trx.Commit();
                    DatabaseCommon.SchemaUpdateID++;

                    // return the columnid for the new column
                    return(new Columnid(
                               columnDefinition.Name,
                               jetColumnid,
                               columndef.coltyp,
                               columndef.cp == JET_CP.ASCII));
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Validates the table definition.
        /// </summary>
        /// <param name="tableDefinition">The table definition.</param>
        /// <exception cref="System.ArgumentException">
        /// Illegal name for a temporary table.;tableDefinition
        /// or
        /// Illegal TableType for a temporary table.;tableDefinition
        /// or
        /// Temporary tables must have at least one column.;tableDefinition
        /// or
        /// Illegal name for a column in a temporary table.;tableDefinition
        /// or
        /// Illegal ColumnFlags for a column in a temporary table.;tableDefinition
        /// or
        /// Default values are not supported for temporary table columns.;tableDefinition
        /// or
        /// Temporary tables of type TableType.Sort and TableType.PreSortTemporary must have an index defined.;tableDefinition
        /// or
        /// Temporary tables may only have a single index defined.;tableDefinition
        /// or
        /// Illegal name for an index in a temporary table.;tableDefinition
        /// or
        /// Illegal IndexFlags for an index in a temporary table.;tableDefinition
        /// or
        /// Illegal or unsupported MaxKeyLength for an index in a temporary table.;tableDefinition
        /// or
        /// No KeyColumns for an index in a temporary table.;tableDefinition
        /// or
        /// Too many KeyColumns for an index in a temporary table.;tableDefinition
        /// or
        /// A KeyColumn for an index in the temporary table refers to a column that doesn't exist.;tableDefinition
        /// or
        /// Conditional columns are not supported for temporary table indices.;tableDefinition
        /// or
        /// Temporary tables of type TableType.PreSortTemporary and TableType.Temporary must have a primary index defined.;tableDefinition
        /// </exception>
        private void ValidateTableDefinition(TableDefinition tableDefinition)
        {
            // validate the table's properties
            DatabaseCommon.CheckName(
                tableDefinition.Name,
                new ArgumentException("Illegal name for a temporary table.", "tableDefinition"));
            if (tableDefinition.Name == null)
            {
                throw new ArgumentException("Illegal name for a temporary table.", "tableDefinition");
            }

            if (
                !(tableDefinition.Type == TableType.Sort || tableDefinition.Type == TableType.PreSortTemporary ||
                  tableDefinition.Type == TableType.Temporary))
            {
                throw new ArgumentException("Illegal TableType for a temporary table.", "tableDefinition");
            }

            // validate all columns
            if (tableDefinition.Columns.Count == 0)
            {
                throw new ArgumentException("Temporary tables must have at least one column.", "tableDefinition");
            }

            foreach (ColumnDefinition columnDefinition in tableDefinition.Columns)
            {
                DatabaseCommon.CheckName(
                    columnDefinition.Name,
                    new ArgumentException("Illegal name for a column in a temporary table.", "tableDefinition"));
                if (columnDefinition.Name == null)
                {
                    throw new ArgumentException("Illegal name for a column in a temporary table.", "tableDefinition");
                }

                if (tableDefinition.Type == TableType.Sort || tableDefinition.Type == TableType.PreSortTemporary)
                {
                    JET_coltyp coltyp = DatabaseCommon.ColtypFromColumnDefinition(columnDefinition);
                    if (coltyp == JET_coltyp.LongText || coltyp == JET_coltyp.LongBinary)
                    {
                        // timestamp when ESE/ESENT supports JET_bitTTIntrinsicLVsOnly
                        DatabaseCommon.CheckEngineVersion(
                            this.IsamSession,
                            DatabaseCommon.ESENTVersion(6, 1, 6492, 0),
                            DatabaseCommon.ESEVersion(14, 0, 46, 0),
                            new ArgumentException(
                                "LongText and LongBinary columns are not supported for columns in a temporary table of type TableType.Sort or TableType.PreSortTemporary on this version of the database engine.",
                                "tableDefinition"));
                    }
                }

                if (0 != (columnDefinition.Flags
                          & ~(ColumnFlags.Fixed
                              | ColumnFlags.Variable
                              | ColumnFlags.Sparse
                              | ColumnFlags.NonNull
                              | ColumnFlags.MultiValued)))
                {
                    throw new ArgumentException("Illegal ColumnFlags for a column in a temporary table.", "tableDefinition");
                }

                if (columnDefinition.DefaultValue != null)
                {
                    throw new ArgumentException("Default values are not supported for temporary table columns.", "tableDefinition");
                }
            }

            // validate all indices
            if (tableDefinition.Indices.Count == 0 &&
                (tableDefinition.Type == TableType.Sort || tableDefinition.Type == TableType.PreSortTemporary))
            {
                throw new ArgumentException("Temporary tables of type TableType.Sort and TableType.PreSortTemporary must have an index defined.", "tableDefinition");
            }

            if (tableDefinition.Indices.Count > 1)
            {
                throw new ArgumentException("Temporary tables may only have a single index defined.", "tableDefinition");
            }

            foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
            {
                DatabaseCommon.CheckName(
                    indexDefinition.Name,
                    new ArgumentException("Illegal name for an index in a temporary table.", "tableDefinition"));
                if (indexDefinition.Name == null)
                {
                    throw new ArgumentException("Illegal name for an index in a temporary table.", "tableDefinition");
                }

                if (0 != (indexDefinition.Flags
                          & ~(IndexFlags.Unique
                              | IndexFlags.Primary
                              | IndexFlags.AllowNull
                              | IndexFlags.SortNullsLow
                              | IndexFlags.SortNullsHigh
                              | IndexFlags.AllowTruncation)))
                {
                    throw new ArgumentException("Illegal IndexFlags for an index in a temporary table.", "tableDefinition");
                }

                // Require AllowTruncation.
                if (0 == (indexDefinition.Flags & IndexFlags.AllowTruncation))
                {
                    throw new ArgumentException("Illegal IndexFlags for an index in a temporary table.", "tableDefinition");
                }

                // 255 in XP.
                long keyMost = this.IsamSession.IsamInstance.IsamSystemParameters.KeyMost;

                if (indexDefinition.MaxKeyLength < 255 || indexDefinition.MaxKeyLength > keyMost)
                {
                    throw new ArgumentException("Illegal or unsupported MaxKeyLength for an index in a temporary table.", "tableDefinition");
                }

                // 12 in XP. 16 in Vista.
                int keyColumnMost = 16;

                if (indexDefinition.KeyColumns.Count == 0)
                {
                    throw new ArgumentException("No KeyColumns for an index in a temporary table.", "tableDefinition");
                }

                if (indexDefinition.KeyColumns.Count > keyColumnMost)
                {
                    throw new ArgumentException("Too many KeyColumns for an index in a temporary table.", "tableDefinition");
                }

                foreach (KeyColumn keyColumn in indexDefinition.KeyColumns)
                {
                    if (!tableDefinition.Columns.Contains(keyColumn.Name))
                    {
                        throw new ArgumentException("A KeyColumn for an index in the temporary table refers to a column that doesn't exist.", "tableDefinition");
                    }
                }

                if (indexDefinition.ConditionalColumns.Count != 0)
                {
                    throw new ArgumentException("Conditional columns are not supported for temporary table indices.", "tableDefinition");
                }

                if ((indexDefinition.Flags & IndexFlags.Primary) == 0 &&
                    (tableDefinition.Type == TableType.PreSortTemporary ||
                     tableDefinition.Type == TableType.Temporary))
                {
                    throw new ArgumentException("Temporary tables of type TableType.PreSortTemporary and TableType.Temporary must have a primary index defined.", "tableDefinition");
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Makes the <see cref="JET_OPENTEMPORARYTABLE"/> object to later open it.
        /// </summary>
        /// <param name="tableDefinition">The table definition.</param>
        /// <returns>The newly created <see cref="JET_OPENTEMPORARYTABLE"/> object.</returns>
        private JET_OPENTEMPORARYTABLE MakeOpenTemporaryTable(TableDefinition tableDefinition)
        {
            JET_OPENTEMPORARYTABLE openTemporaryTable = new JET_OPENTEMPORARYTABLE();

            // allocate room for our columns
            int currentColumndef = 0;

            openTemporaryTable.ccolumn      = tableDefinition.Columns.Count;
            openTemporaryTable.prgcolumndef = new JET_COLUMNDEF[openTemporaryTable.ccolumn];
            openTemporaryTable.prgcolumnid  = new JET_COLUMNID[openTemporaryTable.ccolumn];

            for (int coldef = 0; coldef < openTemporaryTable.ccolumn; ++coldef)
            {
                openTemporaryTable.prgcolumndef[coldef] = new JET_COLUMNDEF();
            }

            // first, collect all the key columns in order and put them as the
            // first columndefs.  we have to do this to guarantee that the TT
            // is sorted properly
            foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
            {
                foreach (KeyColumn keyColumn in indexDefinition.KeyColumns)
                {
                    ColumnDefinition columnDefinition = tableDefinition.Columns[keyColumn.Name];

                    openTemporaryTable.prgcolumndef[currentColumndef].coltyp =
                        DatabaseCommon.ColtypFromColumnDefinition(columnDefinition);
                    openTemporaryTable.prgcolumndef[currentColumndef].cp    = JET_CP.Unicode;
                    openTemporaryTable.prgcolumndef[currentColumndef].cbMax = columnDefinition.MaxLength;
                    openTemporaryTable.prgcolumndef[currentColumndef].grbit = (ColumndefGrbit)columnDefinition.Flags
                                                                              | ColumndefGrbit.TTKey
                                                                              | (keyColumn.IsAscending
                                                                                     ? ColumndefGrbit.None
                                                                                     : ColumndefGrbit.TTDescending);
                    currentColumndef++;
                }
            }

            // next collect the rest of the columns and put them after the key
            // columns, skipping over the columns we already added
            foreach (ColumnDefinition columnDefinition in tableDefinition.Columns)
            {
                bool alreadyAdded = false;
                foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
                {
                    foreach (KeyColumn keyColumn in indexDefinition.KeyColumns)
                    {
                        if (keyColumn.Name.ToLower(CultureInfo.InvariantCulture) == columnDefinition.Name.ToLower(CultureInfo.InvariantCulture))
                        {
                            alreadyAdded = true;
                        }
                    }
                }

                if (!alreadyAdded)
                {
                    openTemporaryTable.prgcolumndef[currentColumndef].coltyp = DatabaseCommon.ColtypFromColumnDefinition(columnDefinition);
                    openTemporaryTable.prgcolumndef[currentColumndef].cp     = JET_CP.Unicode;
                    openTemporaryTable.prgcolumndef[currentColumndef].cbMax  = columnDefinition.MaxLength;
                    openTemporaryTable.prgcolumndef[currentColumndef].grbit  = Converter.ColumndefGrbitFromColumnFlags(columnDefinition.Flags);
                    currentColumndef++;
                }
            }

            // set the index flags
            foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
            {
                openTemporaryTable.pidxunicode = new JET_UNICODEINDEX();

                openTemporaryTable.pidxunicode.lcid = indexDefinition.CultureInfo.LCID;
                UnicodeIndexFlags unicodeIndexFlags = Converter.UnicodeFlagsFromCompareOptions(indexDefinition.CompareOptions);
                openTemporaryTable.pidxunicode.dwMapFlags = Converter.MapFlagsFromUnicodeIndexFlags(unicodeIndexFlags);
            }

            // infer the TT mode of operation and set its grbits accordingly
            bool haveColumnWithLongValue = false;

            foreach (ColumnDefinition columnDefinition in tableDefinition.Columns)
            {
                JET_coltyp coltyp = DatabaseCommon.ColtypFromColumnDefinition(columnDefinition);

                if (coltyp == JET_coltyp.LongText || coltyp == JET_coltyp.LongBinary)
                {
                    haveColumnWithLongValue = true;
                }
            }

            bool haveIndexWithSortNullsHigh = false;

            foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
            {
                if ((indexDefinition.Flags & IndexFlags.SortNullsHigh) != 0)
                {
                    haveIndexWithSortNullsHigh = true;
                }
            }

            if (tableDefinition.Type == TableType.Sort)
            {
                foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
                {
                    if ((indexDefinition.Flags & (IndexFlags.Unique | IndexFlags.Primary)) == 0)
                    {
                        // External Sort without duplicate removal
                        openTemporaryTable.grbit = Server2003Grbits.ForwardOnly
                                                   | (haveColumnWithLongValue
                                                          ? Windows7Grbits.IntrinsicLVsOnly
                                                          : TempTableGrbit.None)
                                                   | (haveIndexWithSortNullsHigh
                                                          ? TempTableGrbit.SortNullsHigh
                                                          : TempTableGrbit.None);
                    }
                    else
                    {
                        // External Sort TT with deferred duplicate removal
                        openTemporaryTable.grbit = TempTableGrbit.Unique
                                                   | (haveColumnWithLongValue
                                                          ? Windows7Grbits.IntrinsicLVsOnly
                                                          : TempTableGrbit.None)
                                                   | (haveIndexWithSortNullsHigh
                                                          ? TempTableGrbit.SortNullsHigh
                                                          : TempTableGrbit.None);
                    }
                }
            }
            else if (tableDefinition.Type == TableType.PreSortTemporary)
            {
                // Pre-sorted B+ Tree TT with deferred duplicate removal
                openTemporaryTable.grbit = TempTableGrbit.Indexed
                                           | TempTableGrbit.Unique
                                           | TempTableGrbit.Updatable
                                           | TempTableGrbit.Scrollable
                                           | (haveColumnWithLongValue
                                                  ? Windows7Grbits.IntrinsicLVsOnly
                                                  : TempTableGrbit.None)
                                           | (haveIndexWithSortNullsHigh
                                                  ? TempTableGrbit.SortNullsHigh
                                                  : TempTableGrbit.None);
            }
            else if (tableDefinition.Type == TableType.Temporary)
            {
                if (tableDefinition.Indices.Count != 0)
                {
                    // B+ Tree TT with immediate duplicate removal
                    openTemporaryTable.grbit = TempTableGrbit.Indexed
                                               | TempTableGrbit.Unique
                                               | TempTableGrbit.Updatable
                                               | TempTableGrbit.Scrollable
                                               | TempTableGrbit.ForceMaterialization
                                               | (haveIndexWithSortNullsHigh
                                                      ? TempTableGrbit.SortNullsHigh
                                                      : TempTableGrbit.None);
                }
                else
                {
                    // B+ Tree TT with a sequential index
                    openTemporaryTable.grbit = TempTableGrbit.Updatable | TempTableGrbit.Scrollable;
                }
            }

            // set the key construction parameters for the TT
            foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
            {
                openTemporaryTable.cbKeyMost   = indexDefinition.MaxKeyLength;
                openTemporaryTable.cbVarSegMac = 0;
            }

            // return the constructed JET_OPENTEMPORARYTABLE (whew!)
            return(openTemporaryTable);
        }
コード例 #4
0
        /// <summary>
        /// Creates a <see cref="TableDefinition"/> object from a <see cref="JET_OPENTEMPORARYTABLE"/>
        /// object, suitable for caching.
        /// </summary>
        /// <param name="tableDefinition">The table definition.</param>
        /// <param name="openTemporaryTable">The open temporary table.</param>
        /// <returns>A <see cref="TableDefinition"/> object suitable for caching.</returns>
        private static TableDefinition MakeTableDefinitionToCache(
            TableDefinition tableDefinition,
            JET_OPENTEMPORARYTABLE openTemporaryTable)
        {
            // set the new table properties
            TableDefinition tableDefinitionToCache = new TableDefinition(tableDefinition.Name, tableDefinition.Type);

            // add the columns complete with the columnids generated when the
            // TT was created
            //
            // NOTE:  this processing loop has to mirror the loop used to generate
            // the columndefs in MakeOpenTemporaryTable
            int currentColumndef = 0;

            foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
            {
                foreach (KeyColumn keyColumn in indexDefinition.KeyColumns)
                {
                    ColumnDefinition columnDefinition = tableDefinition.Columns[keyColumn.Name];

                    Columnid columnid = new Columnid(
                        columnDefinition.Name,
                        openTemporaryTable.prgcolumnid[currentColumndef],
                        DatabaseCommon.ColtypFromColumnDefinition(columnDefinition),
                        columnDefinition.IsAscii);

                    ColumnDefinition columnDefinitionToCache = new ColumnDefinition(columnid);

                    columnDefinitionToCache.Flags     = columnDefinition.Flags;
                    columnDefinitionToCache.MaxLength = columnDefinition.MaxLength;

                    columnDefinitionToCache.ReadOnly = true;

                    tableDefinitionToCache.Columns.Add(columnDefinitionToCache);

                    currentColumndef++;
                }
            }

            // next collect the rest of the columns and put them after the key
            // columns, skipping over the columns we already added
            foreach (ColumnDefinition columnDefinition in tableDefinition.Columns)
            {
                bool alreadyAdded = false;
                foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
                {
                    foreach (KeyColumn keyColumn in indexDefinition.KeyColumns)
                    {
                        if (keyColumn.Name.ToLower(CultureInfo.InvariantCulture) == columnDefinition.Name.ToLower(CultureInfo.InvariantCulture))
                        {
                            alreadyAdded = true;
                        }
                    }
                }

                if (!alreadyAdded)
                {
                    Columnid columnid = new Columnid(
                        columnDefinition.Name,
                        openTemporaryTable.prgcolumnid[currentColumndef],
                        DatabaseCommon.ColtypFromColumnDefinition(columnDefinition),
                        columnDefinition.IsAscii);

                    ColumnDefinition columnDefinitionToCache = new ColumnDefinition(columnid);

                    columnDefinitionToCache.Flags     = columnDefinition.Flags;
                    columnDefinitionToCache.MaxLength = columnDefinition.MaxLength;

                    columnDefinitionToCache.ReadOnly = true;

                    tableDefinitionToCache.Columns.Add(columnDefinitionToCache);

                    currentColumndef++;
                }
            }

            tableDefinitionToCache.Columns.ReadOnly = true;

            // add the indices
            foreach (IndexDefinition indexDefinition in tableDefinition.Indices)
            {
                IndexDefinition indexDefinitionToCache = new IndexDefinition(indexDefinition.Name);

                indexDefinitionToCache.Flags          = indexDefinition.Flags;
                indexDefinitionToCache.Density        = 100;
                indexDefinitionToCache.CultureInfo    = indexDefinition.CultureInfo;
                indexDefinitionToCache.CompareOptions = indexDefinition.CompareOptions;
                indexDefinitionToCache.MaxKeyLength   = indexDefinition.MaxKeyLength;

                foreach (KeyColumn keyColumn in indexDefinition.KeyColumns)
                {
                    Columnid columnid = tableDefinitionToCache.Columns[keyColumn.Name].Columnid;

                    KeyColumn keyColumnToCache = new KeyColumn(columnid, keyColumn.IsAscending);

                    indexDefinitionToCache.KeyColumns.Add(keyColumnToCache);
                }

                indexDefinitionToCache.KeyColumns.ReadOnly = true;

                indexDefinitionToCache.ReadOnly = true;

                tableDefinitionToCache.Indices.Add(indexDefinitionToCache);
            }

            tableDefinitionToCache.Indices.ReadOnly = true;

            // return the table definition
            return(tableDefinitionToCache);
        }