It was possible to for the previous code to completely disable enable_call_graph if an error happened in a trigger function. This should avoid that.
This allows creating triggers on that table without infinite recursion.
Now that table usage tracking works for all callers, the graphs quickly grew bigger than necessary. Now the only information we show is the name of the table and whether it was written to, or only read from. UPDATE and DELETE both require a seq/idx scan before they can modify the data so we can't realiably tell the user that "this table is only written to"; it would only work for INSERTs.
After some testing it occurred that the feature introduced in 6071135 was not enough even for our purposes since EXECUTE prepared_statement(); counts as two statements, and thus will not track table information. :-( The way to fix this was to take a snapshot of pg_stat_act_user_tables before entering the top level function, and then comparing that to the data in the table before leaving the top level function. This, however, comes with a significant performance penalty, and I don't see any obvious way to make things significantly better without modifying PG itself. One low-hanging fruit would be to avoid using the pg_stat_xact_*_tables views and do the hash lookups ourselves, but I'm not sure how much that would help. Maybe in the future we could look into changing things in PG, but for now, this is all we got..
We will never find that information since we don't (currently) have it.
This looks a lot better, but also makes the code even more complex. :-( Also includes a small refactoring to create_graphs.pl: I didn't like the way the IsSubGraph and EntryFunctionOid information was parsed from the GraphID, so I added extra columns for both of them. I originally wanted to change the name of the "main graphs" from "graph1" to EntryFunctionName, but that seemed a bit harder to do. Maybe some other day..
We actually multiplied all the stats by the number of confrelids each table had. :-(