Modify function to use it in multiple triggers
Answers so far still suffer from one or the other shortcoming.


Use the USING clause of EXECUTE to pass values. Do not concatenate the text representation of values into the SQL string. Expensive and error-prone.
Properly escape all identifiers when used in dynamic SQL to defend against sneaky errors with double quoted identifiers and possible SQL injection. Even if you think you do not need it. Do it on principal.

But this would be an error waiting to happen:

'_bit' || quote_ident(TG_TABLE_NAME)

For a table name "MyTable" this would produce _bit"MyTable" - syntactical nonsense. It must be:

quote_ident('_bit' || TG_TABLE_NAME)


Or use format('... %I ...', '_bit' || TG_TABLE_NAME)


The only correct solution is what you added to your question yourself:

CREATE OR REPLACE FUNCTION bitacoratabla()
  RETURNS trigger AS
$func$
BEGIN
   EXECUTE format('INSERT INTO %I SELECT $1.*', '_bit' || TG_TABLE_NAME)
   USING OLD;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;


Detailed explanation:


INSERT with dynamic table name in trigger function


But why does it work with an additional column?


  the other table has the old values and an additional column to store the date data


This happens to work as long as the additional column in the target table comes last because, quoting the manual on INSERT:


  If no list of column names is given at all, the default is all the
  columns of the table in their declared order; or the first N column
  names, if there are only N columns supplied by the VALUES clause or query.


So you better be sure the additional column(s) come last in the table definition of the target table, and all other columns are listed in matching order, now and in all future - or you must add an explicit target column list (which would prevent a generic function to begin with).