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"