anchor.diff:        [],
         New_opts
        ).
  +
  +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  +%%
  +%% Altering table type:
  +%%
  +%%   set -> bag: copy, at worst
  +%%   ordered_set -> bag: copy, at worst
  +%%   set -> ordered_set: copy
  +%%   ordered_set -> set: copy, at worst
  +%%   bag -> *: copy, with possible data loss
  +%%
  +%% Thus, when moving from bag to some other type, we
  +%% run the risk of data loss. Otherwise, copying is safe.
  +%%
  +%% Note that mnesia appears not to support changing the type of a
  +%% table at runtime.  We could generically do this (A -> B):
  +%%
  +%% 1/ create A', identical to A
  +%% 2/ copy data of A to A'
  +%% 3/ delete A
  +%% 4/ recreate A with new options
  +%% 5/ copy data of A' to A
  +%% 6/ delete A'
  +%%
  +%% If mnesia had a way to rename a table, we could instead do the
  +%% cheaper option (saving one copy!):
  +%%
  +%% 1'/ create new table A'
  +%% 2'/ copy data from A to A'
  +%% 3'/ delete A
  +%% 4'/ rename A' to A
  +%%
  +%% Note: if A is a bag, multiple values per key will lead to data loss
  +%% when copied to bag.  We could detect data loss before this point.
  +%% 
  +%% Note that the general case can change table type, storage type
  +%% and what nodes it can occur on. We should try to be intelligent
  +%% in these cases, e.g., stay out of disc_only_copies as long as
  +%% possible. [The even more general case can also change other
  +%% table options, but let's leave that for elsewhere.]
  +%%
  +%% Finally, generic copying also supports cases such as changing
  +%% other table options apart from type (e.g., storage options,
  +%% local storage, and whatnot), where copying may be required
  +%% to properly transition to the new table definition.
  +%%  Basically, copying the table to one with the new options seems
  +%% to solve MOST issues with table changes (not data loss though, nor
  +%% layout; not sure about distribution).
  +%%
  +%% UNFINISHED
  +%% - changes storage type at same time!
  +%%   * could also do layout xform in second copy, I think
  +%% - check that it works properly on distributed system
  +%% - check that it works for fragments ...
  +%% - storage type of TEMP COPY should be settable
  +%%   * ram_copies should be very fast (but needs more memory)
  +%%   * storing table on "better set of nodes" than old_opts MIGHT be a win
  +%%   * after copying, change table copies to those of New_opts
  +%%     (= replicate to new nodes) then do the final copying
  +%% - is there some easier way to do this? existing mnesia operation?
  +%% - idea: optimize for memory: explicit copying from node A to B?
  +%%   that way, we do not need to build a temp table (probably)
  +
  +alter_table_type(Tab, Old_opts, New_opts, Old_type, New_type, Actions) ->
  +    TmpTab = temp_table_name(Tab),
  +    RecName = record_name_of(Tab, Old_opts),
  +    Tmp_opts = adjust_options(RecName, Old_opts),
  +    [{mnesia, create_table, [TmpTab, Tmp_opts]},
  +     {schematool_helper, copy_table, [Tab, TmpTab]},
  +     {mnesia, delete_table, [Tab]},
  +     {mnesia, create_table, [Tab, New_opts]},
  +     case {Old_type, New_type} of
  +	 {set, _} ->
  +	     {schematool_helper, copy_table, [TmpTab, Tab]};
  +	 {ordered_set, _} ->
  +	     {schematool_helper, copy_table, [TmpTab, Tab]};
  +	 {bag, _} ->
  +	     %% UNFINISHED
  +	     %% - get collision policy Coll from New_opts if possible
  +	     %%   'keep_some_value' is default 
  +	     %%   (= just copy and overwrite)
  +	     %%   - if target is 'bag' too, not lossy
  +	     Coll = keep_some_value,
  +	     {schematool_helper, lossy_copy_table, [Coll, TmpTab, Tab]}
  +     end,
  +     %% Finally delete the temporary table
  +     {mnesia, delete_table, [TmpTab]}
  +     |Actions].
  +
  +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  +%% Adjusting the nodes of the temporary table:
  +%% - the end action is to copy to the nodes in New_opts
  +%% - thus, no inherent need to have temp table on all
  +%%   old nodes
  +%% - however, MIGHT be better to copy slow tables to ram_copies
  +%%   on origin node before transferring?
  +%%   * if old table is disc_copies_only, could get slow
  +%%   * but using ram_copies could eat too much memory
  +%% - if table has multiple storage types, might be better
  +%%   to just choose to copy from the "fast" types?
  +%%
  +%% Clearly, some optimization thinking should be used
  +%% here to minimize the cost. Creating the temp table
  +%% on the old nodes should be safe, however.
  +%%
  +%% Other adjustments:
  +%% - adjust layout while copying? (combine with alter_table_layout)
  +%% - lossy copy can be done first, ie inherit type from New_opts
  +%%   (since this reducs the amount of data)
  +
  +%% Opts are the options of the old table, adjust them to suit the
  +%% temporary table.
  +%%
  +%% 1/ set record_name to that used by the old table
  +%% 2/ [adjust storage type and nodes to optimize copying]
  +%%
  +%% UNFINISHED
  +%% - adjust storage type and nodes used etc
  +
  +adjust_options(Tab, Opts) ->
  +    record_name_of(Tab, Opts).
  +
  +record_name_of(Tab, [{record_name, _Rec}|Opts]=Lst) ->
  +    %% we have an explicit record name, use that
  +    Lst;
  +record_name_of(Tab, [Opt|Opts]) ->
  +    %% skip
  +    [Opt|record_name_of(Tab, Opts)];
  +record_name_of(Tab, []) ->
  +    %% In this case, there is no explicit record_name def
  +    %% so insert one
  +    [{record_name, Tab}].
  +	
  +%% essentially a gensym
  +%%
  +%% - to be completely safe, should first check whether TmpName already
  +%%   is an atom (list_to_existing_atom/1 fails, or something)
  +
  +temp_table_name(Tab) ->
  +    {A, B, C} = erlang:now(),
  +    TmpName = 
  +	lists:flatten(
  +	  io_lib:format("~p_~p_~p_~p",
  +			[Tab, A, B, C])),
  +    list_to_atom(TmpName).
   
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   %% Alter table layout, using schematool_transform
  
positive.code:     Acts1 = alter_table_layout(Tab, Old_opts, New_opts, []),
      Acts2 = alter_storage_type(Tab, Old_opts, New_opts, []),
      Acts3 = alter_indexes(Tab, Old_opts, New_opts),
      [Acts0, Acts1, Acts2, Acts3].
  
  %% Returns a list of instructions
  %% - perhaps with a priority so we can sort them
  
negative.code: %% - are cases 2/3 errors instead? investigate
  
  alter_storage(_Tab, {_Node, {Type, Type}}) ->
      %% No change
      [];
  alter_storage(Tab, {Node, {undefined, Type}}) ->
      {mnesia, add_table_copy, [Tab, Node, Type]};
  