/// <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"); } } }
/// <summary> /// Creates a single table with the specified definition in the database /// </summary> /// <param name="tableDefinition">The table definition.</param> /// <exception cref="EsentTableDuplicateException"> /// Thrown when the table definition overlaps with an already existing table. /// </exception> /// <exception cref="System.ArgumentException">A MaxKeyLength > 255 is not supported for indices over a temporary table on this version of the database engine.;tableDefinition</exception> public override void CreateTable(TableDefinition tableDefinition) { lock (this.IsamSession) { this.CheckDisposed(); // validate the table definition for creating a TT this.ValidateTableDefinition(tableDefinition); // convert the given table definition into an JET_OPENTEMPORARYTABLE // struct that we will use to create the TT JET_OPENTEMPORARYTABLE openTemporaryTable = this.MakeOpenTemporaryTable(tableDefinition); // check if the TT already exists if (this.Exists(tableDefinition.Name)) { throw new EsentTableDuplicateException(); } // do not allow the TT to be created if the session is in a // transaction. we disallow this to sidestep the problem where // JET will automatically close (and destroy) the TT if the // current level of the transaction is aborted if (this.IsamSession.TransactionLevel > 0) { // NOTE: i'm thinking that this requirement is pretty lame, // especially since it only hits us on an abort. I am going // to allow this for now and see what happens // throw new ArgumentException( "We do not currently allow you to create temp tables while inside of a transaction." ); } // create the TT JET_TABLEID tableid = new JET_TABLEID(); if (DatabaseCommon.CheckEngineVersion( this.IsamSession, DatabaseCommon.ESENTVersion(6, 0, 6000, 0), DatabaseCommon.ESEVersion(8, 0, 685, 0))) { VistaApi.JetOpenTemporaryTable(this.IsamSession.Sesid, openTemporaryTable); tableid = openTemporaryTable.tableid; } else { if (openTemporaryTable.cbKeyMost > 255) { throw new ArgumentException("A MaxKeyLength > 255 is not supported for indices over a temporary table on this version of the database engine.", "tableDefinition"); } Api.JetOpenTempTable2( this.IsamSession.Sesid, openTemporaryTable.prgcolumndef, openTemporaryTable.prgcolumndef.Length, openTemporaryTable.pidxunicode.lcid, openTemporaryTable.grbit, out tableid, openTemporaryTable.prgcolumnid); } // re-create the TT's schema to reflect the created TT TableDefinition tableDefinitionToCache = MakeTableDefinitionToCache(tableDefinition, openTemporaryTable); // cache the TT and its handle TempTableHandle tempTableHandle = new TempTableHandle( tableDefinitionToCache.Name, this.IsamSession.Sesid, tableid, tableDefinitionToCache.Type == TableType.Sort || tableDefinitionToCache.Type == TableType.PreSortTemporary); this.Tables.Add(tableDefinitionToCache); this.TempTableHandles.Add(tempTableHandle); this.IsamSession.IsamInstance.TempTableHandles.Add(tempTableHandle); } }