OSDN Git Service

Update copyright for 2021.
[ludiafuncs/ludia_funcs.git] / ludia_funcs.c
index e7fd254..d1396e1 100644 (file)
@@ -1,5 +1,6 @@
 /*-------------------------------------------------------------------------
  *
+ * Copyright (c) 2016-2021, ludia_funcs Development Group
  * Copyright (c) 2006-2015, NTT DATA Corporation
  * All rights reserved.
  *
 PG_MODULE_MAGIC;
 
 /* Last update date of ludia_funcs */
-#define        PGS2_LAST_UPDATE        "2015.09.10"
+#define        PGS2_LAST_UPDATE        "2019.10.04"
 
 /* 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;
@@ -97,6 +121,7 @@ static bool                  EscapeSnippetKeyword(char **s, size_t *slen);
 /* 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
@@ -119,6 +144,7 @@ static void CleanupTextPorterTmpFiles(void);
 
 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);
@@ -131,11 +157,12 @@ _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,
@@ -182,6 +209,17 @@ _PG_init(void)
                                                           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 */
@@ -276,6 +314,14 @@ pgs2textporter1(PG_FUNCTION_ARGS)
                                         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).
                 */
@@ -286,6 +332,10 @@ pgs2textporter1(PG_FUNCTION_ARGS)
                                                         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,
@@ -408,6 +458,15 @@ assign_textporter_option(const char *newval, void *extra)
        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
@@ -625,13 +684,15 @@ EscapeSnippetKeyword(char **s, size_t *slen)
        *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;
@@ -661,13 +722,15 @@ GetSennaQuery(char *str, size_t len)
                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;
        }
@@ -808,9 +871,11 @@ static inline void
 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))
@@ -906,16 +971,20 @@ pgs2norm(PG_FUNCTION_ARGS)
                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
 
-               PG_RETURN_TEXT_P(pnstrdup(norm_result, norm_reslen));
+               result = (text *) palloc(norm_reslen);
+               memcpy(result, norm_result, norm_reslen);
+               PG_RETURN_TEXT_P(result);
        }
 
        /* Confirm that database encoding is UTF-8 */
@@ -984,7 +1053,7 @@ retry:
        }
 
 #ifdef PGS2_DEBUG
-       if (pgs2_enable_debug)
+       if (pgs2_enable_debug == PGS2_ENABLE_DEBUG_ON)
        {
                char    *tmp = text_to_cstring(str);
 
@@ -992,6 +1061,8 @@ retry:
                         (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);