/* GUC variables */
#ifdef PGS2_DEBUG
-static bool pgs2_enable_debug = false;
-#endif
+typedef enum pgs2_enable_debug_type
+{
+ PGS2_ENABLE_DEBUG_OFF, /* logs no debug log */
+ PGS2_ENABLE_DEBUG_TERSE, /* logs tersely, e.g., just names of
+ functions */
+ PGS2_ENABLE_DEBUG_ON /* logs detailed infomation */
+} pgs2_enable_debug_type;
+
+/* We accept all the likely variants of "on" and "off" */
+static const struct config_enum_entry pgs2_enable_debug_options[] = {
+ {"off", PGS2_ENABLE_DEBUG_OFF, false},
+ {"terse", PGS2_ENABLE_DEBUG_TERSE, false},
+ {"on", PGS2_ENABLE_DEBUG_ON, false},
+ {"true", PGS2_ENABLE_DEBUG_ON, true},
+ {"false", PGS2_ENABLE_DEBUG_OFF, true},
+ {"yes", PGS2_ENABLE_DEBUG_ON, true},
+ {"no", PGS2_ENABLE_DEBUG_OFF, true},
+ {"1", PGS2_ENABLE_DEBUG_ON, true},
+ {"0", PGS2_ENABLE_DEBUG_OFF, true},
+ {NULL, 0, false}
+};
+
+static int pgs2_enable_debug = PGS2_ENABLE_DEBUG_OFF;
+#endif /* PGS2_DEBUG */
+
static char *pgs2_last_update = NULL;
static int norm_cache_limit = -1;
static bool escape_snippet_keyword = false;
/* GUC variables for pgs2textpoter1 */
static int textporter_error = ERROR;
static unsigned int textporter_option = TEXTPORTER_OPTION;
+static bool textporter_exit_on_segv = false;
/*
* This variable is a dummy that doesn't do anything, except in some
static bool check_textporter_option(char **newval, void **extra, GucSource source);
static void assign_textporter_option(const char *newval, void *extra);
+static void textporter_exit_on_segv_handler(SIGNAL_ARGS);
#endif /* TEXTPORTER */
void _PG_init(void);
#ifdef PGS2_DEBUG
/* Define custom GUC variable for debugging */
- DefineCustomBoolVariable("ludia_funcs.enable_debug",
+ DefineCustomEnumVariable("ludia_funcs.enable_debug",
"Emit ludia_funcs debugging output.",
NULL,
&pgs2_enable_debug,
- false,
+ PGS2_ENABLE_DEBUG_OFF,
+ pgs2_enable_debug_options,
PGC_USERSET,
0,
NULL,
assign_textporter_option,
NULL);
+ DefineCustomBoolVariable("ludia_funcs.textporter_exit_on_segv",
+ "Terminate session when textporter causes segmentation fault.",
+ NULL,
+ &textporter_exit_on_segv,
+ false,
+ PGC_USERSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+
/* Clean up remaining textporter temporary files */
CleanupTextPorterTmpFiles();
#endif /* TEXTPORTER */
errmsg("could not close temporary file \"%s\": %m", txtfile)));
/*
+ * If textporter_exit_on_segv option is enabled, segmentation fault
+ * caused by textporter will terminate only this connection and
+ * not lead to the server crash.
+ */
+ if (textporter_exit_on_segv)
+ pqsignal(SIGSEGV, textporter_exit_on_segv_handler);
+
+ /*
* Run TextPorter to read text data from application file (appfile)
* to temporary file (txtfile).
*/
TEXTPORTER_BBIGENDIAN, textporter_option,
TEXTPORTER_OPTION1, TEXTPORTER_SIZE,
TEXTPORTER_CSV_C);
+
+ if (textporter_exit_on_segv)
+ pqsignal(SIGSEGV, SIG_DFL);
+
if (ret != 0)
{
ereport(textporter_error,
textporter_option = *((unsigned int *) extra);
}
+static void
+textporter_exit_on_segv_handler(SIGNAL_ARGS)
+{
+ ereport(FATAL,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ errmsg("terminating PostgreSQL server process due to "
+ "segmentation fault by textporter")));
+}
+
#else /* TEXTPORTER */
Datum
*slen = ep - *s;
#ifdef PGS2_DEBUG
- if (pgs2_enable_debug)
+ if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_ON)
{
char *tmp = pnstrdup(*s, *slen);
elog(LOG, "escaped snippet keyword: %s", tmp);
pfree(tmp);
}
+ else if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_TERSE)
+ elog(LOG, "escaped snippet keyword");
#endif
return true;
escape_snippet_keyword == guc_cache)
{
#ifdef PGS2_DEBUG
- if (pgs2_enable_debug)
+ if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_ON)
{
char *tmp = pnstrdup(str, len);
elog(LOG, "GetSennaQuery(): quick exit: %s", tmp);
pfree(tmp);
}
+ else if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_TERSE)
+ elog(LOG, "GetSennaQuery(): quick exit");
#endif
return query_cache;
}
pgs2malloc(void **buf, long *buflen, long needed, long maxlen)
{
#ifdef PGS2_DEBUG
- if (pgs2_enable_debug)
+ if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_ON)
elog(LOG, "pgs2malloc(): buflen %ld, needed %ld, maxlen %ld",
*buflen, needed, maxlen);
+ else if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_TERSE)
+ elog(LOG, "pgs2malloc()");
#endif
if (*buf != NULL && *buflen >= needed && (*buflen <= maxlen || maxlen == 0))
strncmp(norm_cache, s, slen) == 0)
{
#ifdef PGS2_DEBUG
- if (pgs2_enable_debug)
+ if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_ON)
{
char *tmp = text_to_cstring(str);
elog(LOG, "pgs2norm(): quick exit: %s", tmp);
pfree(tmp);
}
+ else if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_TERSE)
+ elog(LOG, "pgs2norm(): quick exit");
#endif
result = (text *) palloc(norm_reslen);
}
#ifdef PGS2_DEBUG
- if (pgs2_enable_debug)
+ if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_ON)
{
char *tmp = text_to_cstring(str);
(norm_cache == NULL) ? "unset" : "set", tmp);
pfree(tmp);
}
+ else if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_TERSE)
+ elog(LOG, "pgs2norm(): complete");
#endif
PG_RETURN_TEXT_P(result);