Hi, Recent developments on the "backup manifest" thread and others have caused me to take an interest in making more code that has historically been backend-only accessible in frontend environments also. I'm pretty sure I'm not alone in having often wished for more backend-only facilities to be available in front-end code, because many of them are very convenient, but up until now I haven't been motivated enough to do much about it.
Probably the thorniest problem is the backend's widespread dependence on ereport() and elog(). Now, it would not be enormously difficult to code up something that will sigsetjmp() and siglongjmp() in front-end code just as we do in backend code, but I think it would be largely missing the point. Just jumping out of a function some place and back to the top level is not very safe, because you will tend to leak resources and leave data structures in broken states. In the backend, we've made this safe via transaction cleanup, which arranges to release resources, including memory, at the proper times. Getting this to work everywhere and for all the kinds of resources that matter has been a pretty significant undertaking; while frontend environments tend to be simpler, I think it's likely to take a good deal of work and thought to figure it all out. There's another problem, too: when ereport() is used in the backend, it reports not only an error message but a bunch of other things like an error code, an optional error detail, and an error context. It might be good to introduce some of these concepts on the frontend side, but it will be confusing if frontend errors start getting reported just like backend errors, so here again I feel we need to think carefully. That being said, not all uses of ereport() and elog() are created equal. Sometimes, they are just used to report warnings, which typically don't contain much more than a primary message, and sometimes they are used to report can't-happen conditions, which ERROR in backend code and could probably just print a message and exit() in frontend code. Providing a general way to do this kind of thing seems a lot easier than solving the whole problem, and it would allow us to avoid continuing to copy stuff like this: #ifndef FRONTEND #define pg_log_warning(...) elog(WARNING, __VA_ARGS__) #else #include "common/logging.h" #endif We have two copies of that already, and I don't think we should continue to add more. So, what I'd like to propose is a pair of macros, one of which arranges for a warning of an appropriate sort for either a backend or frontend environment, and the other of which is used for a can't happen condition that should either ERROR or just exit. Taking a page from my Perl programming background, I propose to call these pg_carp() and pg_croak(), although I'm not in love with those names so let the bikeshedding commence. Something like: #ifdef FRONTEND #define pg_croak(...) do { pg_log_fatal(__VA_ARGS__); exit(1) } while (0) #define pg_carp(...) pg_log_warning(__VA_ARGS__); #else #define pg_croak(...) elog(ERROR, __VA_ARGS__) #define pg_carp(...) elog(WARNING, __VA_ARGS__) #endif It is of course somewhat questionable to consider a "croak" as effectively *fatal* on the frontend side but only ERROR rather than FATAL on the backend side, but for the kinds of things I'm looking at it seems like the most useful definition. If the JSON parser goes horribly wrong to due to some logic bug, it is neither useful nor friendly to terminate the session, but a frontend tool is probably fine for it to just exit. The user perception will be, in each case, that the last command they attempted (either from the command-line or from psql, as the case may be) failed but that they are free to enter more commands without needing to start a new session (either of psql or bash or whatever). Thoughts? -- Robert Haas EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company