erlang mnesia - illegal record info

不问归期 提交于 2019-12-22 07:05:01

问题


I am trying to have a function that ensures the table I need is already created and if not to create it. Here's the sample:

ensure_table_exists(Table, MnesiaTables, Nodes) ->
case lists:member(Table, MnesiaTables) of
    true ->
        throw({error, db_might_have_already_been_created});
    false ->
        mnesia:create_table(Table, [{disc_copies, Nodes},
                {attributes, record_info(fields, Table)}]), 
        ok  
end.

The issue is that when compiling I get the error: illegal record info. It might have to do that record_info is resolved at compile time or that the second argument to record info should actually be a record that can be retrieved from the source code ?


回答1:


Yes, all record related things including record_info/2 are resolved at compile time. This means that record and field names must be known at compile time. This is the reason for the compiler error.

I don't think your function is really too defensive in that what you are doing is signaling a more specific error. It would be another matter if you were to return {error, ...}.

One last point is that if you mean to raise an exception you should not use throw/1 but instead use erlang:error/1. throw is intended for non-local return (caught with a catch) while erlang:error is intended for raising an exception. In many cases the result may be the same but the actual error value may be misleading (nocatch). It is always better the clearer you can show your intention, which in this case is signaling an error.

P.S. Yes, I know that catch also catches errors/exits as well. This was intentional. In a perfect world maybe catch should only catch throws and try only errors/exits.




回答2:


Unfortunately record_info is not really a function even if it looks like one.

You can verify that by testing the following. Create a file:

 -module(something).
 -record(a, {}).

Start the Erlang shell:

 > rr(something).
 [a]
 > record_info(fields, a).
 []
 > A = a.
 > record_info(fields, A).
 * 2: illegal record info

So my recommendation would be to either use a macro or a specialised function for the record_info part.

To answer your original question. Use something like:

 tables() ->
   [?TABLE_MACRO(tablename),
    ?TABLE_MACRO(tablename2),
    ...].

where TABLE_MACRO is something like:

 -define(TABLE_MACRO(Table), fun() ->
      mnesia:create_table(Table, [{disc_copies, Nodes},
               {attributes, record_info(fields, Table)}])
      end).

and then have a function using something like the below.

 [case CreateTable of
   {aborted, {already_exists, _}} -> ok;
   {atomic, ok} -> ok
  end || CreateTable <- tables()].

Yuck! Can be cleaned up quite a bit, but hopefully you understand the general idea.

  • Macro instead of variable use.
  • Match on both {atomic, ok} and {aborted, {already_exists, _TableName}}



回答3:


You might want to have a look to Ulf Wiger's exprecs.

Reading from the description:

The module is a parse transform allowing you to export records. The transform adds accessor functions for instantiating, inspecting and modifying records, without having to introduce compile-time dependencies between modules.

Said that, your function sounds a bit defensive to me. The following page explains why it's a bad habit to program defensively in Erlang:

http://www.erlang.se/doc/programming_rules.shtml#HDR11



来源:https://stackoverflow.com/questions/3685035/erlang-mnesia-illegal-record-info

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!