public void AlterTable( string schemaName, string tableName, G.List<AlterAction> alist, Exec e )
  {
    Table t = (Table) GetTable( schemaName, tableName, e );

    var names = new G.List<string>( t.Cols.Names );
    var types = new G.List<DataType>( t.Cols.Types );
    var map = new G.List<int>();
    for ( int i = 0; i < names.Count; i += 1 ) map.Add( i );

    foreach ( AlterAction aa in alist )
    {
      int ix = names.IndexOf( aa.Name );
      if ( aa.Operation != Action.Add && ix == -1 )
        e.Error( "Column " + aa.Name + " not found" );

      switch ( aa.Operation )
      {
        case Action.Add: 
          if ( ix != -1 ) e.Error( "Column " + aa.Name + " already exists" );
          names.Add( aa.Name );
          types.Add( aa.Type );
          map.Add( 0 );
          Sql( "INSERT INTO sys.Column( Table, Name, Type ) VALUES ( " + t.TableId + "," + Util.Quote(aa.Name) + "," + (int)aa.Type + ")" );
          break;
        case Action.Drop:
          names.RemoveAt( ix );
          types.RemoveAt( ix );
          map.RemoveAt( ix );
          Sql( "DELETE FROM sys.Column WHERE Table = " + t.TableId + " AND Name = " + Util.Quote(aa.Name) ); 
          Sql( "EXEC sys.DroppedColumn(" + t.TableId + "," + ix + ")" );
          break;
        case Action.ColumnRename:
          names.RemoveAt( ix );
          names.Insert( ix, aa.NewName );
          Sql( "UPDATE sys.Column SET Name = " + Util.Quote(aa.NewName) + " WHERE Table=" + t.TableId + " AND Name = " + Util.Quote(aa.Name) );
          break;
        case Action.Modify:
          if ( DTI.Base( aa.Type ) != DTI.Base( types[ ix ] ) )
            e.Error( "Modify cannot change base type" );
          if ( DTI.Scale( aa.Type ) != DTI.Scale( types[ ix ] ) )
            e.Error( "Modify cannot change scale" );
          types.RemoveAt( ix );
          types.Insert( ix, aa.Type );
          Sql( "UPDATE sys.Column SET Type = " + (int)aa.Type + " WHERE Table=" + t.TableId + " AND Name = " + Util.Quote(aa.Name) );
          Sql( "EXEC sys.ModifiedColumn(" + t.TableId + "," + ix + ")" );
          break;
      }
    }
    var newcols = ColInfo.New( names, types );
    t.AlterData( newcols, map.ToArray() );
    Sql( "EXEC sys.RecreateModifiedIndexes()" );
    t.OpenIndexes();
    ResetCache();
  }
  public TableExpression GetTableOrView( string schemaName, string name, Exec e )
  {
    Schema schema = GetSchema( schemaName, true, e );
    TableExpression result = schema.GetCachedTable( name ); 
    if ( result != null ) return result;

    bool isView; string definition;
    long tid = ReadTableId( schema, name, out isView, out definition );
    if ( tid < 0 ) e.Error( schemaName + "." + name + " not found" );

    if ( isView )
    {
      TableExpression te = e.LoadView( definition, schemaName + "." + name );
      te.TableId = tid;
      schema.TableDict[ name ] = te;
      return te;
    }
    else
    {
      // Fetch the Column Information from the SysColumn table.
      var names = new G.List<string>(); 
      var types = new G.List<DataType>();
      names.Add( "Id" ); types.Add( DataType.Bigint ); // Add the pre-defined "id" column.

      // Use SysColumnIndex to avoid scanning the entire SysColumn table.
      var start = new LongStart( tid );
      var r = new RowCursor( SysColumn );

      foreach( IndexFileRecord ixr in SysColumnIndex.From( start.Compare, false ) )
      {
        if ( ixr.Col[0].L == tid )
        {
          r.Get( ixr.Col[1].L );
          names.Add( (string) r.V[2]._O );
          types.Add( (DataType)r.V[3].L );
        }
        else break;
      }

      Table t = new Table( this, schema, name, ColInfo.New(names,types), tid );
      t.OpenIndexes();
      return t;
    }
  }
 public ColInfo Get()
 {
   ColInfo result = ColInfo.New( Names, Types );
   Names = null;   
   return result;
 }