Add an optional missing_ok argument to SQL function current_setting().
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jul 2015 20:40:55 +0000 (16:40 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Jul 2015 20:41:07 +0000 (16:41 -0400)
This allows convenient checking for existence of a GUC from SQL, which is
particularly useful when dealing with custom variables.

David Christensen, reviewed by Jeevan Chalke

contrib/tsearch2/tsearch2.c
doc/src/sgml/func.sgml
src/backend/utils/misc/guc.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/include/utils/guc.h
src/test/regress/expected/guc.out
src/test/regress/sql/guc.sql

index 143dabba407d6e34670f80e785dd5434a1b4c12b..4354c5b0904d27efb47e3390006b5e82fb35ecc6 100644 (file)
@@ -363,7 +363,7 @@ tsa_tsearch2(PG_FUNCTION_ARGS)
                tgargs[i + 1] = trigger->tgargs[i];
 
        tgargs[1] = pstrdup(GetConfigOptionByName("default_text_search_config",
-                                                                                         NULL));
+                                                                                         NULL, false));
        tgargs_old = trigger->tgargs;
        trigger->tgargs = tgargs;
        trigger->tgnargs++;
index 99923f46bcaf292cf4acd2c1ec16eb960aa91933..76f77cb0fcf2f7e63d0d0d3419690db79d71178e 100644 (file)
@@ -16444,7 +16444,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         <indexterm>
          <primary>current_setting</primary>
         </indexterm>
-        <literal><function>current_setting(<parameter>setting_name</parameter>)</function></literal>
+        <literal><function>current_setting(<parameter>setting_name</parameter> [, <parameter>missing_ok</parameter> ])</function></literal>
        </entry>
        <entry><type>text</type></entry>
        <entry>get current value of setting</entry>
@@ -16492,6 +16492,11 @@ SELECT current_setting('datestyle');
  ISO, MDY
 (1 row)
 </programlisting>
+
+    If there is no setting named <parameter>setting_name</parameter>,
+    <function>current_setting</function> throws an error
+    unless <parameter>missing_ok</parameter> is supplied and is
+    <literal>true</literal>.
    </para>
 
    <para>
index 0356ecb48219c05cc8b13a97bee9c46b54d15e52..595a609989d379d556a1e162370bde25d36403ed 100644 (file)
@@ -7131,7 +7131,7 @@ ExtractSetVariableArgs(VariableSetStmt *stmt)
                case VAR_SET_VALUE:
                        return flatten_set_variable_args(stmt->name, stmt->args);
                case VAR_SET_CURRENT:
-                       return GetConfigOptionByName(stmt->name, NULL);
+                       return GetConfigOptionByName(stmt->name, NULL, false);
                default:
                        return NULL;
        }
@@ -7200,7 +7200,7 @@ set_config_by_name(PG_FUNCTION_ARGS)
                                                         true, 0, false);
 
        /* get the new current value */
-       new_value = GetConfigOptionByName(name, NULL);
+       new_value = GetConfigOptionByName(name, NULL, false);
 
        /* Convert return string to text */
        PG_RETURN_TEXT_P(cstring_to_text(new_value));
@@ -7627,7 +7627,7 @@ GetPGVariableResultDesc(const char *name)
                const char *varname;
 
                /* Get the canonical spelling of name */
-               (void) GetConfigOptionByName(name, &varname);
+               (void) GetConfigOptionByName(name, &varname, false);
 
                /* need a tuple descriptor representing a single TEXT column */
                tupdesc = CreateTemplateTupleDesc(1, false);
@@ -7650,7 +7650,7 @@ ShowGUCConfigOption(const char *name, DestReceiver *dest)
        char       *value;
 
        /* Get the value and canonical spelling of name */
-       value = GetConfigOptionByName(name, &varname);
+       value = GetConfigOptionByName(name, &varname, false);
 
        /* need a tuple descriptor representing a single TEXT column */
        tupdesc = CreateTemplateTupleDesc(1, false);
@@ -7734,19 +7734,30 @@ ShowAllGUCConfig(DestReceiver *dest)
 }
 
 /*
- * Return GUC variable value by name; optionally return canonical
- * form of name.  Return value is palloc'd.
+ * Return GUC variable value by name; optionally return canonical form of
+ * name.  If the GUC is unset, then throw an error unless missing_ok is true,
+ * in which case return NULL.  Return value is palloc'd (but *varname isn't).
  */
 char *
-GetConfigOptionByName(const char *name, const char **varname)
+GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
 {
        struct config_generic *record;
 
        record = find_option(name, false, ERROR);
        if (record == NULL)
+       {
+               if (missing_ok)
+               {
+                       if (varname)
+                               *varname = NULL;
+                       return NULL;
+               }
+
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
                           errmsg("unrecognized configuration parameter \"%s\"", name)));
+       }
+
        if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser())
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@@ -8033,14 +8044,34 @@ GetNumConfigOptions(void)
 Datum
 show_config_by_name(PG_FUNCTION_ARGS)
 {
-       char       *varname;
+       char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
        char       *varval;
 
-       /* Get the GUC variable name */
-       varname = TextDatumGetCString(PG_GETARG_DATUM(0));
+       /* Get the value */
+       varval = GetConfigOptionByName(varname, NULL, false);
+
+       /* Convert to text */
+       PG_RETURN_TEXT_P(cstring_to_text(varval));
+}
+
+/*
+ * show_config_by_name_missing_ok - equiv to SHOW X command but implemented as
+ * a function.  If X does not exist, suppress the error and just return NULL
+ * if missing_ok is TRUE.
+ */
+Datum
+show_config_by_name_missing_ok(PG_FUNCTION_ARGS)
+{
+       char       *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
+       bool            missing_ok = PG_GETARG_BOOL(1);
+       char       *varval;
 
        /* Get the value */
-       varval = GetConfigOptionByName(varname, NULL);
+       varval = GetConfigOptionByName(varname, NULL, missing_ok);
+
+       /* return NULL if no such variable */
+       if (varval == NULL)
+               PG_RETURN_NULL();
 
        /* Convert to text */
        PG_RETURN_TEXT_P(cstring_to_text(varval));
index 965a53cbfda46c102f974646d06a5065d0f925d7..44ce2b3a6200689085a69e1bd19972f0530f0c6d 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201506282
+#define CATALOG_VERSION_NO     201507021
 
 #endif
index be3a8fba1bed439e3f0fbb3ba6f43e3212e30ac8..6fd1278d1b2448a3ab120f25a81f801a61f5a962 100644 (file)
@@ -3067,6 +3067,8 @@ DESCR("convert bitstring to int8");
 
 DATA(insert OID = 2077 (  current_setting      PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ show_config_by_name _null_ _null_ _null_ ));
 DESCR("SHOW X as a function");
+DATA(insert OID = 3294 (  current_setting      PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 25 "25 16" _null_ _null_ _null_ _null_ _null_ show_config_by_name_missing_ok _null_ _null_ _null_ ));
+DESCR("SHOW X as a function, optionally no error for missing variable");
 DATA(insert OID = 2078 (  set_config           PGNSP PGUID 12 1 0 0 0 f f f f f f v 3 0 25 "25 25 16" _null_ _null_ _null_ _null_ _null_ set_config_by_name _null_ _null_ _null_ ));
 DESCR("SET X as a function");
 DATA(insert OID = 2084 (  pg_show_all_settings PGNSP PGUID 12 1 1000 0 0 f f f f t t s 0 0 2249 "" "{25,25,25,25,25,25,25,25,25,25,25,1009,25,25,25,23,16}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{name,setting,unit,category,short_desc,extra_desc,context,vartype,source,min_val,max_val,enumvals,boot_val,reset_val,sourcefile,sourceline,pending_restart}" _null_ _null_ show_all_settings _null_ _null_ _null_ ));
@@ -4866,8 +4868,8 @@ DESCR("GIN support");
 DATA(insert OID = 3301 (  jsonb_concat    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3802 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_concat _null_ _null_ _null_ ));
 DATA(insert OID = 3302 (  jsonb_delete    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3802 "3802 25" _null_ _null_ _null_ _null_ _null_ jsonb_delete _null_ _null_ _null_ ));
 DATA(insert OID = 3303 (  jsonb_delete    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3802 "3802 23" _null_ _null_ _null_ _null_ _null_ jsonb_delete_idx _null_ _null_ _null_ ));
-DATA(insert OID = 3304 (  jsonb_delete_path       PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3802 "3802 1009" _null_ _null_ _null_ _null_ _null_ jsonb_delete_path _null_ _null_ _null_ ));
-DATA(insert OID = 3305 (  jsonb_set       PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 3802 "3802 1009 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_set _null_ _null_ _null_ ));
+DATA(insert OID = 3304 (  jsonb_delete_path    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3802 "3802 1009" _null_ _null_ _null_ _null_ _null_ jsonb_delete_path _null_ _null_ _null_ ));
+DATA(insert OID = 3305 (  jsonb_set    PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 3802 "3802 1009 3802 16" _null_ _null_ _null_ _null_ _null_ jsonb_set _null_ _null_ _null_ ));
 DESCR("Set part of a jsonb");
 DATA(insert OID = 3306 (  jsonb_pretty    PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "3802" _null_ _null_ _null_ _null_ _null_ jsonb_pretty _null_ _null_ _null_ ));
 DESCR("Indented text from jsonb");
index 98556725c8e02a01df2fc3f08772916cacbf5e61..fcb0bf0ce8e94c376c683dcf7a8bb18d2b83b0a7 100644 (file)
@@ -1114,6 +1114,7 @@ extern Datum quote_nullable(PG_FUNCTION_ARGS);
 
 /* guc.c */
 extern Datum show_config_by_name(PG_FUNCTION_ARGS);
+extern Datum show_config_by_name_missing_ok(PG_FUNCTION_ARGS);
 extern Datum set_config_by_name(PG_FUNCTION_ARGS);
 extern Datum show_all_settings(PG_FUNCTION_ARGS);
 extern Datum show_all_file_settings(PG_FUNCTION_ARGS);
index 49ec3840af3fce0560f0c755268634f6ef6aa243..dc167f9bb5c88e23fa94fdcc82c088848c158ae9 100644 (file)
@@ -365,7 +365,8 @@ extern int set_config_option(const char *name, const char *value,
                                  GucAction action, bool changeVal, int elevel,
                                  bool is_reload);
 extern void AlterSystemSetConfigFile(AlterSystemStmt *setstmt);
-extern char *GetConfigOptionByName(const char *name, const char **varname);
+extern char *GetConfigOptionByName(const char *name, const char **varname,
+                                         bool missing_ok);
 extern void GetConfigOptionByNum(int varnum, const char **values, bool *noshow);
 extern int     GetNumConfigOptions(void);
 
index 4f0065cb7efb845652b520f1ab8a2ae20645c962..fdb9b5cddaf95430d90b74376ec0e2793825de52 100644 (file)
@@ -720,6 +720,37 @@ select myfunc(1), current_setting('work_mem');
  2MB    | 2MB
 (1 row)
 
+-- check current_setting()'s behavior with invalid setting name
+select current_setting('nosuch.setting');  -- FAIL
+ERROR:  unrecognized configuration parameter "nosuch.setting"
+select current_setting('nosuch.setting', false);  -- FAIL
+ERROR:  unrecognized configuration parameter "nosuch.setting"
+select current_setting('nosuch.setting', true) is null;
+ ?column? 
+----------
+ t
+(1 row)
+
+-- after this, all three cases should yield 'nada'
+set nosuch.setting = 'nada';
+select current_setting('nosuch.setting');
+ current_setting 
+-----------------
+ nada
+(1 row)
+
+select current_setting('nosuch.setting', false);
+ current_setting 
+-----------------
+ nada
+(1 row)
+
+select current_setting('nosuch.setting', true);
+ current_setting 
+-----------------
+ nada
+(1 row)
+
 -- Normally, CREATE FUNCTION should complain about invalid values in
 -- function SET options; but not if check_function_bodies is off,
 -- because that creates ordering hazards for pg_dump
index 3de8a6b55d658ea33f977f0774f9ffa5a9102176..6a062a0a5bad828bd5b65a6cbac52aac1da590a7 100644 (file)
@@ -258,6 +258,19 @@ select myfunc(0);
 select current_setting('work_mem');
 select myfunc(1), current_setting('work_mem');
 
+-- check current_setting()'s behavior with invalid setting name
+
+select current_setting('nosuch.setting');  -- FAIL
+select current_setting('nosuch.setting', false);  -- FAIL
+select current_setting('nosuch.setting', true) is null;
+
+-- after this, all three cases should yield 'nada'
+set nosuch.setting = 'nada';
+
+select current_setting('nosuch.setting');
+select current_setting('nosuch.setting', false);
+select current_setting('nosuch.setting', true);
+
 -- Normally, CREATE FUNCTION should complain about invalid values in
 -- function SET options; but not if check_function_bodies is off,
 -- because that creates ordering hazards for pg_dump