On Sun, Jun 20, 2004 at 08:49:22PM -0400, Tom Lane wrote:

Regarding GUC, a WIP report:

> Given patches for inval.c and guc.c, I would say that the patch is
> functionally close enough to done that we could commit to including
> it in 7.5 --- the other stuff could be wrapped up post-feature-freeze.

I figured I could save the values whenever they are going to change, and
restore them if the subtransaction aborts.  This seems to work fine
(lightly tested).

I still have to figure out how to handle allocation for string vars, but
I thought I'd post the patch for others to see.  Please let me know if
it's too ugly.  (This patch misses the pieces in xact.c and xact.h but
I'm sure the concept is clear.)

I'll post a full patch once the missing deferred trigger stuff works.
With the patches I posted to inval.c I think this fulfills the
requirements, barring the performance issues raised.

Comments?

-- 
Alvaro Herrera (<alvherre[a]dcc.uchile.cl>)
"No single strategy is always right (Unless the boss says so)"
(Larry Wall)
Index: guc.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql-server/src/backend/utils/misc/guc.c,v
retrieving revision 1.211
diff -c -w -b -B -c -r1.211 guc.c
*** guc.c       11 Jun 2004 03:54:54 -0000      1.211
--- guc.c       24 Jun 2004 23:41:42 -0000
***************
*** 25,30 ****
--- 25,31 ----
  #include "utils/guc.h"
  #include "utils/guc_tables.h"
  
+ #include "access/xact.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/async.h"
***************
*** 54,59 ****
--- 55,61 ----
  #include "tcop/tcopprot.h"
  #include "utils/array.h"
  #include "utils/builtins.h"
+ #include "utils/memutils.h"
  #include "utils/pg_locale.h"
  #include "pgstat.h"
  
***************
*** 76,81 ****
--- 78,85 ----
  static const char *assign_log_destination(const char *value,
                                bool doit, GucSource source);
  
+ static void SaveGucVariable(struct config_generic *conf);
+ 
  #ifdef HAVE_SYSLOG
  extern char *Syslog_facility;
  extern char *Syslog_ident;
***************
*** 105,110 ****
--- 109,115 ----
                                                   GucSource source);
  static bool assign_stage_log_stats(bool newval, bool doit, GucSource source);
  static bool assign_log_stats(bool newval, bool doit, GucSource source);
+ static bool assign_transaction_read_only(bool newval, bool doit, GucSource source);
  
  
  /*
***************
*** 172,177 ****
--- 177,183 ----
  static int    max_index_keys;
  static int    max_identifier_length;
  static int    block_size;
+ static int    nesting_level;
  static bool integer_datetimes;
  
  /* Macros for freeing malloc'd pointers only if appropriate to do so */
***************
*** 801,807 ****
                        GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
                },
                &XactReadOnly,
!               false, NULL, NULL
        },
        {
                {"add_missing_from", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
--- 807,813 ----
                        GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
                },
                &XactReadOnly,
!               false, assign_transaction_read_only, NULL
        },
        {
                {"add_missing_from", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
***************
*** 1311,1316 ****
--- 1317,1333 ----
                BLCKSZ, BLCKSZ, BLCKSZ, NULL, NULL
        },
  
+       {
+               /* XXX probably it's a bad idea for this to be GUC_REPORT. */
+               {"nesting_level", PGC_INTERNAL, UNGROUPED,
+                       gettext_noop("Shows the current transaction nesting level"),
+                       NULL,
+                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_REPORT
+               },
+               &nesting_level,
+               0, 0, INT_MAX, NULL, NULL
+       },
+ 
        /* End-of-list marker */
        {
                {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL
***************
*** 2001,2014 ****
                        return find_option(map_old_guc_names[i+1]);
        }
  
!       /* Check if the name is qualified, and if so, check if the qualifier
         * maps to a custom variable class.
         */
        dot = strchr(name, GUC_QUALIFIER_SEPARATOR);
        if(dot != NULL && is_custom_class(name, dot - name))
!               /*
!                * Add a placeholder variable for this name
!                */
                return (struct config_generic*)add_placeholder_variable(name);
  
        /* Unknown name */
--- 2018,2030 ----
                        return find_option(map_old_guc_names[i+1]);
        }
  
!       /*
!        * Check if the name is qualified, and if so, check if the qualifier
         * maps to a custom variable class.
         */
        dot = strchr(name, GUC_QUALIFIER_SEPARATOR);
        if(dot != NULL && is_custom_class(name, dot - name))
!               /* Add a placeholder variable for this name */
                return (struct config_generic*)add_placeholder_variable(name);
  
        /* Unknown name */
***************
*** 2899,2904 ****
--- 2915,2922 ----
                                                return false;
                                        }
  
+                               SaveGucVariable(record);
+ 
                                if (changeVal || makeDefault)
                                {
                                        if (changeVal)
***************
*** 3004,3009 ****
--- 3022,3029 ----
                                                return false;
                                        }
  
+                               SaveGucVariable(record);
+ 
                                if (changeVal || makeDefault)
                                {
                                        if (changeVal)
***************
*** 3099,3104 ****
--- 3119,3126 ----
                                                return false;
                                        }
  
+                               SaveGucVariable(record);
+ 
                                if (changeVal || makeDefault)
                                {
                                        if (changeVal)
***************
*** 3257,3262 ****
--- 3279,3286 ----
                                        }
                                }
  
+                               SaveGucVariable(record);
+ 
                                guc_string_workspace = NULL;
  
                                if (changeVal || makeDefault)
***************
*** 4744,4749 ****
--- 4768,4909 ----
        return newarray;
  }
  
+ typedef struct SaveGucBoolVar
+ {
+       bool    variable;
+       bool    session_val;
+       bool    tentative_val;
+ } SaveGucBoolVar;
+ 
+ typedef struct SaveGucIntVar
+ {
+       int             variable;
+       int             session_val;
+       int             tentative_val;
+ } SaveGucIntVar;
+ 
+ typedef struct SaveGucRealVar
+ {
+       double  variable;
+       double  session_val;
+       double  tentative_val;
+ } SaveGucRealVar;
+ 
+ typedef struct SaveGucStringVar
+ {
+       char    *variable;
+       char    *session_val;
+       char    *tentative_val;
+ } SaveGucStringVar;
+ 
+ typedef struct SaveGucVar
+ {
+       struct config_generic *record;
+       union {
+               SaveGucBoolVar          boolvar;
+               SaveGucIntVar           intvar;
+               SaveGucRealVar          realvar;
+               SaveGucStringVar        stringvar;
+       };
+ } SaveGucVar;
+ 
+ void
+ SaveGucVariable(struct config_generic *record)
+ {
+       MemoryContext old_cxt;
+       SaveGucVar *save;
+ 
+       /*
+        * don't bother if we are not inside a subtransaction.
+        */
+       if (!IsSubTransaction())
+               return;
+ 
+       /* 
+        * no point in saving this.
+        */
+       if (record->name == "nesting_level")
+               return;
+ 
+       old_cxt = MemoryContextSwitchTo(CommitContext);
+ 
+       save = (SaveGucVar *) palloc(sizeof(SaveGucVar));
+       save->record = record;
+ 
+       switch (record->vartype)
+       {
+               case PGC_BOOL:
+                       save->boolvar.variable = *((struct config_bool 
*)record)->variable;
+                       save->boolvar.session_val = ((struct config_bool 
*)record)->session_val;
+                       save->boolvar.tentative_val = ((struct config_bool 
*)record)->tentative_val;
+                       break;
+ 
+               case PGC_INT:
+                       save->intvar.variable = *((struct config_int 
*)record)->variable;
+                       save->intvar.session_val = ((struct config_int 
*)record)->session_val;
+                       save->intvar.tentative_val = ((struct config_int 
*)record)->tentative_val;
+                       break;
+ 
+               case PGC_REAL:
+                       save->realvar.variable = *((struct config_real 
*)record)->variable;
+                       save->realvar.session_val = ((struct config_real 
*)record)->session_val;
+                       save->realvar.tentative_val = ((struct config_real 
*)record)->tentative_val;
+                       break;
+ 
+ #ifdef NOT_USED
+               case PGC_STRING:
+                       save->stringvar.variable = pstrdup(*((struct config_string 
*)record)->variable);
+                       save->stringvar.session_val = ((struct config_string 
*)record)->session_val;
+                       save->stringvar.tentative_val = ((struct config_string 
*)record)->tentative_val;
+                       break;
+ #endif
+ 
+               default:
+                       elog(DEBUG2, "ignoring unsupported GUC vartype %d", 
record->vartype);
+ 
+       }
+ 
+       TransactionSaveGucVar(save);
+       MemoryContextSwitchTo(old_cxt);
+ }
+ 
+ void
+ RestoreGucVariable(void *pointer)
+ {
+       SaveGucVar *save = (SaveGucVar *)pointer;
+ 
+       switch (save->record->vartype)
+       {
+               case PGC_BOOL:
+                       *((struct config_bool *)save->record)->variable = 
save->boolvar.variable;
+                       ((struct config_bool *)save->record)->session_val = 
save->boolvar.session_val;
+                       ((struct config_bool *)save->record)->tentative_val = 
save->boolvar.tentative_val;
+                       break;
+ 
+               case PGC_INT:
+                       *((struct config_int *)save->record)->variable = 
save->intvar.variable;
+                       ((struct config_int *)save->record)->session_val = 
save->intvar.session_val;
+                       ((struct config_int *)save->record)->tentative_val = 
save->intvar.tentative_val;
+                       break;
+ 
+               case PGC_REAL:
+                       *((struct config_real *)save->record)->variable = 
save->realvar.variable;
+                       ((struct config_real *)save->record)->session_val = 
save->realvar.session_val;
+                       ((struct config_real *)save->record)->tentative_val = 
save->realvar.tentative_val;
+                       break;
+ 
+ #ifdef NOT_USED
+               case PGC_STRING:
+                       *((struct config_string *)save->record)->variable = 
save->stringvar.variable;
+                       ((struct config_string *)save->record)->session_val = 
save->stringvar.session_val;
+                       ((struct config_string *)save->record)->tentative_val = 
save->stringvar.tentative_val;
+                       break;
+ #endif
+ 
+               default:
+                       elog(DEBUG2, "ignoring saved value type %d", 
save->record->vartype);
+       }
+ }
  
  /*
   * assign_hook subroutines
***************
*** 5133,5137 ****
--- 5293,5306 ----
        return true;
  }
  
+ static bool
+ assign_transaction_read_only(bool newval, bool doit, GucSource source)
+ {
+       if (doit && source >= PGC_S_INTERACTIVE && IsSubTransaction())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("cannot set transaction read only mode inside 
a subtransaction")));
+       return true;
+ }
  
  #include "guc-file.c"
---------------------------(end of broadcast)---------------------------
TIP 8: explain analyze is your friend

Reply via email to