summaryrefslogtreecommitdiff
path: root/src/backend/commands/variable.c
blob: 8d1e8a1b3c5aa57110564269fc5377d9beeade25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
/*-------------------------------------------------------------------------
 *
 * variable.c
 *		Routines for handling of 'SET var TO',
 *		'SHOW var' and 'RESET var' statements.
 *
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.57.2.1 2002/08/22 05:27:41 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <ctype.h>
#include <time.h>

#include "access/xact.h"
#include "catalog/pg_shadow.h"
#include "commands/variable.h"
#include "miscadmin.h"
#include "optimizer/cost.h"
#include "optimizer/paths.h"
#include "parser/parse_expr.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/guc.h"
#include "utils/tqual.h"

#ifdef MULTIBYTE
#include "mb/pg_wchar.h"
#else
/* Grand unified hard-coded badness */
#define pg_get_client_encoding_name()  "SQL_ASCII"
#define GetDatabaseEncodingName() "SQL_ASCII"
#endif


static bool show_datestyle(void);
static bool reset_datestyle(void);
static bool parse_datestyle(List *);
static bool show_timezone(void);
static bool reset_timezone(void);
static bool parse_timezone(List *);

static bool show_XactIsoLevel(void);
static bool reset_XactIsoLevel(void);
static bool parse_XactIsoLevel(List *);
static bool show_random_seed(void);
static bool reset_random_seed(void);
static bool parse_random_seed(List *);

static bool show_client_encoding(void);
static bool reset_client_encoding(void);
static bool parse_client_encoding(List *);
static bool show_server_encoding(void);
static bool reset_server_encoding(void);
static bool parse_server_encoding(List *);


/*
 * get_token
 *		Obtain the next item in a comma-separated list of items,
 *		where each item can be either "word" or "word=word".
 *		The "word=word" form is only accepted if 'val' is not NULL.
 *		Words are any sequences not containing whitespace, ',', or '='.
 *		Whitespace can appear between the words and punctuation.
 *
 * 'tok': receives a pointer to first word of item, or NULL if none.
 * 'val': if not NULL, receives a pointer to second word, or NULL if none.
 * 'str': start of input string.
 *
 * Returns NULL if input string contained no more words, else pointer
 * to just past this item, which can be used as 'str' for next call.
 * (If this is the last item, returned pointer will point at a null char,
 * so caller can alternatively check for that instead of calling again.)
 *
 * NB: input string is destructively modified by placing null characters
 * at ends of words!
 *
 * A former version of this code avoided modifying the input string by
 * returning palloc'd copies of the words.  However, we want to use this
 * code early in backend startup to parse the PGDATESTYLE environment var,
 * and palloc/pfree aren't initialized at that point.  Cleanest answer
 * seems to be to palloc in SetPGVariable() so that we can treat the string
 * as modifiable here.
 */
static char *
get_token(char **tok, char **val, char *str)
{
	char		ch;

	*tok = NULL;
	if (val != NULL)
		*val = NULL;

	if (!str || *str == '\0')
		return NULL;

	/* skip leading white space */
	while (isspace((unsigned char) *str))
		str++;

	/* end of string? then return NULL */
	if (*str == '\0')
		return NULL;

	if (*str == ',' || *str == '=')
		elog(ERROR, "Syntax error near \"%s\": empty setting", str);

	/* OK, at beginning of non-empty item */
	*tok = str;

	/* Advance to end of word */
	while (*str && !isspace((unsigned char) *str) &&
		   *str != ',' && *str != '=')
		str++;

	/* Terminate word string for caller */
	ch = *str;
	*str = '\0';

	/* Skip any whitespace */
	while (isspace((unsigned char) ch))
		ch = *(++str);

	/* end of string? */
	if (ch == '\0')
		return str;
	/* delimiter? */
	if (ch == ',')
		return ++str;

	/* Had better be '=', and caller must be expecting it */
	if (val == NULL || ch != '=')
		elog(ERROR, "Syntax error near \"%s\"", str);

	/* '=': get the value */
	str++;

	/* skip whitespace after '=' */
	while (isspace((unsigned char) *str))
		str++;

	if (*str == ',' || *str == '\0')
		elog(ERROR, "Syntax error near \"=%s\"", str);

	/* OK, at beginning of non-empty value */
	*val = str;

	/* Advance to end of word */
	while (*str && !isspace((unsigned char) *str) && *str != ',')
		str++;

	/* Terminate word string for caller */
	ch = *str;
	*str = '\0';

	/* Skip any whitespace */
	while (isspace((unsigned char) ch))
		ch = *(++str);

	/* end of string? */
	if (ch == '\0')
		return str;
	/* delimiter? */
	if (ch == ',')
		return ++str;

	elog(ERROR, "Syntax error near \"%s\"", str);

	return str;
}


/*
 * DATESTYLE
 *
 * NOTE: set_default_datestyle() is called during backend startup to check
 * if the PGDATESTYLE environment variable is set.	We want the env var
 * to determine the value that "RESET DateStyle" will reset to!
 */

/* These get initialized from the "master" values in init/globals.c */
static int	DefaultDateStyle;
static bool DefaultEuroDates;

static bool
parse_datestyle_internal(char *value)
{
	char	   *tok;
	int			dcnt = 0,
				ecnt = 0;

	if (value == NULL)
		return reset_datestyle();

	while ((value = get_token(&tok, NULL, value)) != 0)
	{
		/* Ugh. Somebody ought to write a table driven version -- mjl */

		if (!strcasecmp(tok, "ISO"))
		{
			DateStyle = USE_ISO_DATES;
			dcnt++;
		}
		else if (!strcasecmp(tok, "SQL"))
		{
			DateStyle = USE_SQL_DATES;
			dcnt++;
		}
		else if (!strncasecmp(tok, "POSTGRESQL", 8))
		{
			DateStyle = USE_POSTGRES_DATES;
			dcnt++;
		}
		else if (!strcasecmp(tok, "GERMAN"))
		{
			DateStyle = USE_GERMAN_DATES;
			dcnt++;
			EuroDates = TRUE;
			if ((ecnt > 0) && (!EuroDates))
				ecnt++;
		}
		else if (!strncasecmp(tok, "EURO", 4))
		{
			EuroDates = TRUE;
			if ((dcnt <= 0) || (DateStyle != USE_GERMAN_DATES))
				ecnt++;
		}
		else if ((!strcasecmp(tok, "US"))
				 || (!strncasecmp(tok, "NONEURO", 7)))
		{
			EuroDates = FALSE;
			if ((dcnt <= 0) || (DateStyle == USE_GERMAN_DATES))
				ecnt++;
		}
		else if (!strcasecmp(tok, "DEFAULT"))
		{
			DateStyle = DefaultDateStyle;
			EuroDates = DefaultEuroDates;
			ecnt++;
		}
		else
			elog(ERROR, "Bad value for date style (%s)", tok);
	}

	if (dcnt > 1 || ecnt > 1)
		elog(NOTICE, "Conflicting settings for date");

	return TRUE;
}

static bool
parse_datestyle(List *args)
{
	char	   *value;

	if (args == NULL)
		return reset_datestyle();

	Assert(IsA(lfirst(args), A_Const));

	value = ((A_Const *) lfirst(args))->val.val.str;

	return parse_datestyle_internal(value);
}

static bool
show_datestyle(void)
{
	char		buf[64];
	char	   *dstyle;

	switch (DateStyle)
	{
		case USE_ISO_DATES:
			dstyle = "ISO";
			break;
		case USE_SQL_DATES:
			dstyle = "SQL";
			break;
		case USE_GERMAN_DATES:
			dstyle = "German";
			break;
		default:
			dstyle = "Postgres";
			break;
	}

	snprintf(buf, sizeof(buf), "DateStyle is %s with %s conventions",
			 dstyle, EuroDates ? "European" : "US (NonEuropean");

	elog(NOTICE, buf, NULL);

	return TRUE;
}

static bool
reset_datestyle(void)
{
	DateStyle = DefaultDateStyle;
	EuroDates = DefaultEuroDates;

	return TRUE;
}

void
set_default_datestyle(void)
{
	char	   *DBDate;

	/*
	 * Initialize from compile-time defaults in init/globals.c. NB: this
	 * is a necessary step; consider PGDATESTYLE="DEFAULT".
	 */
	DefaultDateStyle = DateStyle;
	DefaultEuroDates = EuroDates;

	/* If the environment var is set, override compiled-in values */
	DBDate = getenv("PGDATESTYLE");
	if (DBDate == NULL)
		return;

	/*
	 * Make a modifiable copy --- overwriting the env var doesn't seem
	 * like a good idea, even though we currently won't look at it again.
	 * Note that we cannot use palloc at this early stage of
	 * initialization.
	 */
	DBDate = strdup(DBDate);

	/*
	 * Parse desired setting into DateStyle/EuroDates Use
	 * parse_datestyle_internal() to avoid any palloc() issues per above -
	 * thomas 2001-10-15
	 */
	parse_datestyle_internal(DBDate);

	free(DBDate);

	/* And make it the default for future RESETs */
	DefaultDateStyle = DateStyle;
	DefaultEuroDates = EuroDates;
}


/* Timezone support
 * Working storage for strings is allocated with an arbitrary size of 64 bytes.
 */

static char *defaultTZ = NULL;
static char TZvalue[64];
static char tzbuf[64];

/*
 *
 * TIMEZONE
 *
 */
/* parse_timezone()
 * Handle SET TIME ZONE...
 * Try to save existing TZ environment variable for later use in RESET TIME ZONE.
 * Accept an explicit interval per SQL9x, though this is less useful than a full time zone.
 * - thomas 2001-10-11
 */
static bool
parse_timezone(List *args)
{
	List	   *arg;
	TypeName   *type;

	if (args == NULL)
		return reset_timezone();

	Assert(IsA(args, List));

	foreach(arg, args)
	{
		A_Const    *p;

		Assert(IsA(arg, List));
		p = lfirst(arg);
		Assert(IsA(p, A_Const));

		type = p->typename;
		if (type != NULL)
		{
			if (strcmp(type->name, "interval") == 0)
			{
				Interval   *interval;

				interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
																 CStringGetDatum(p->val.val.str),
																 ObjectIdGetDatum(InvalidOid),
																 Int32GetDatum(type->typmod)));
				if (interval->month != 0)
					elog(ERROR, "SET TIME ZONE illegal INTERVAL; month not allowed");
				CTimeZone = interval->time;
			}
			else if (strcmp(type->name, "float8") == 0)
			{
				float8		time;

				time = DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(p->val.val.str)));
				CTimeZone = time * 3600;
			}

			/*
			 * We do not actually generate an integer constant in gram.y
			 * so this is not used...
			 */
			else if (strcmp(type->name, "int4") == 0)
			{
				int32		time;

				time = p->val.val.ival;
				CTimeZone = time * 3600;
			}
			else
			{
				elog(ERROR, "Unable to process SET TIME ZONE command; internal coding error");
			}

			HasCTZSet = true;
		}
		else
		{
			char	   *tok;
			char	   *value;

			value = p->val.val.str;

			while ((value = get_token(&tok, NULL, value)) != 0)
			{
				/* Not yet tried to save original value from environment? */
				if (defaultTZ == NULL)
				{
					/* found something? then save it for later */
					if ((defaultTZ = getenv("TZ")) != NULL)
						strncpy(TZvalue, defaultTZ, sizeof(TZvalue));

					/* found nothing so mark with an invalid pointer */
					else
						defaultTZ = (char *) -1;
				}

				snprintf(tzbuf, sizeof(tzbuf), "TZ=%s", tok);
				if (putenv(tzbuf) != 0)
					elog(ERROR, "Unable to set TZ environment variable to %s", tok);

				tzset();
			}

			HasCTZSet = false;
		}
	}

	return TRUE;
}	/* parse_timezone() */

static bool
show_timezone(void)
{
	char	   *tzn;

	if (HasCTZSet)
	{
		Interval	interval;

		interval.month = 0;
		interval.time = CTimeZone;

		tzn = DatumGetCString(DirectFunctionCall1(interval_out, IntervalPGetDatum(&interval)));
	}
	else
		tzn = getenv("TZ");

	if (tzn != NULL)
		elog(NOTICE, "Time zone is '%s'", tzn);
	else
		elog(NOTICE, "Time zone is unset");

	return TRUE;
}	/* show_timezone() */

/* reset_timezone()
 * Set TZ environment variable to original value.
 * Note that if TZ was originally not set, TZ should be cleared.
 * unsetenv() works fine, but is BSD, not POSIX, and is not available
 * under Solaris, among others. Apparently putenv() called as below
 * clears the process-specific environment variables.
 * Other reasonable arguments to putenv() (e.g. "TZ=", "TZ", "") result
 * in a core dump (under Linux anyway).
 * - thomas 1998-01-26
 */
static bool
reset_timezone(void)
{
	if (HasCTZSet)
		HasCTZSet = false;

	/* no time zone has been set in this session? */
	else if (defaultTZ == NULL)
	{
	}

	/* time zone was set and original explicit time zone available? */
	else if (defaultTZ != (char *) -1)
	{
		snprintf(tzbuf, sizeof(tzbuf), "TZ=%s", TZvalue);
		if (putenv(tzbuf) != 0)
			elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue);
		tzset();
	}

	/*
	 * otherwise, time zone was set but no original explicit time zone
	 * available
	 */
	else
	{
		strcpy(tzbuf, "=");
		if (putenv(tzbuf) != 0)
			elog(ERROR, "Unable to clear TZ environment variable");
		tzset();
	}

	return TRUE;
}	/* reset_timezone() */



/*
 *
 * SET TRANSACTION
 *
 */

static bool
parse_XactIsoLevel(List *args)
{
	char	   *value;

	if (args == NULL)
		return reset_XactIsoLevel();

	Assert(IsA(lfirst(args), A_Const));

	value = ((A_Const *) lfirst(args))->val.val.str;

	if (SerializableSnapshot != NULL)
	{
		elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
		return TRUE;
	}

	if (strcmp(value, "serializable") == 0)
		XactIsoLevel = XACT_SERIALIZABLE;
	else if (strcmp(value, "read committed") == 0)
		XactIsoLevel = XACT_READ_COMMITTED;
	else
		elog(ERROR, "invalid transaction isolation level: %s", value);

	return TRUE;
}

static bool
show_XactIsoLevel(void)
{

	if (XactIsoLevel == XACT_SERIALIZABLE)
		elog(NOTICE, "TRANSACTION ISOLATION LEVEL is SERIALIZABLE");
	else
		elog(NOTICE, "TRANSACTION ISOLATION LEVEL is READ COMMITTED");
	return TRUE;
}

static bool
reset_XactIsoLevel(void)
{

	if (SerializableSnapshot != NULL)
	{
		elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
		return TRUE;
	}

	XactIsoLevel = DefaultXactIsoLevel;

	return TRUE;
}


/*
 * Random number seed
 */
static bool
parse_random_seed(List *args)
{
	char	   *value;
	double		seed = 0;

	if (args == NULL)
		return reset_random_seed();

	Assert(IsA(lfirst(args), A_Const));

	value = ((A_Const *) lfirst(args))->val.val.str;

	sscanf(value, "%lf", &seed);
	DirectFunctionCall1(setseed, Float8GetDatum(seed));

	return (TRUE);
}

static bool
show_random_seed(void)
{
	elog(NOTICE, "Seed for random number generator is unavailable");
	return (TRUE);
}

static bool
reset_random_seed(void)
{
	double		seed = 0.5;

	DirectFunctionCall1(setseed, Float8GetDatum(seed));
	return (TRUE);
}


/*
 * MULTIBYTE-related functions
 *
 * If MULTIBYTE support was not compiled, we still allow these variables
 * to exist, but you can't set them to anything but "SQL_ASCII".  This
 * minimizes interoperability problems between non-MB servers and MB-enabled
 * clients.
 */

static bool
parse_client_encoding(List *args)
{
	char	   *value;

#ifdef MULTIBYTE
	int			encoding;
#endif

	if (args == NULL)
		return reset_client_encoding();

	Assert(IsA(lfirst(args), A_Const));

	value = ((A_Const *) lfirst(args))->val.val.str;

#ifdef MULTIBYTE
	encoding = pg_valid_client_encoding(value);
	if (encoding < 0)
	{
		if (value)
			elog(ERROR, "Client encoding '%s' is not supported", value);
		else
			elog(ERROR, "No client encoding is specified");
	}
	else
	{
		if (pg_set_client_encoding(encoding) < 0)
		{
			elog(ERROR, "Conversion between %s and %s is not supported",
				 value, GetDatabaseEncodingName());
		}
	}
#else
	if (value &&
		strcasecmp(value, pg_get_client_encoding_name()) != 0)
		elog(ERROR, "Client encoding %s is not supported", value);
#endif
	return TRUE;
}

static bool
show_client_encoding(void)
{
	elog(NOTICE, "Current client encoding is '%s'",
		 pg_get_client_encoding_name());
	return TRUE;
}

static bool
reset_client_encoding(void)
{
#ifdef MULTIBYTE
	int			encoding;
	char	   *env = getenv("PGCLIENTENCODING");

	if (env)
	{
		encoding = pg_char_to_encoding(env);
		if (encoding < 0)
			encoding = GetDatabaseEncoding();
	}
	else
		encoding = GetDatabaseEncoding();

	pg_set_client_encoding(encoding);
#endif
	return TRUE;
}

/* Called during MULTIBYTE backend startup ... */
void
set_default_client_encoding(void)
{
	reset_client_encoding();
}


static bool
parse_server_encoding(List *args)
{
	elog(NOTICE, "SET SERVER_ENCODING is not supported");
	return TRUE;
}

static bool
show_server_encoding(void)
{
	elog(NOTICE, "Current server encoding is '%s'", GetDatabaseEncodingName());
	return TRUE;
}

static bool
reset_server_encoding(void)
{
	elog(NOTICE, "RESET SERVER_ENCODING is not supported");
	return TRUE;
}



/* SetPGVariable()
 * Dispatcher for handling SET commands.
 * Special cases ought to be removed and handled separately by TCOP
 */
void
SetPGVariable(const char *name, List *args)
{
	if (strcasecmp(name, "datestyle") == 0)
		parse_datestyle(args);
	else if (strcasecmp(name, "timezone") == 0)
		parse_timezone(args);
	else if (strcasecmp(name, "XactIsoLevel") == 0)
		parse_XactIsoLevel(args);
	else if (strcasecmp(name, "client_encoding") == 0)
		parse_client_encoding(args);
	else if (strcasecmp(name, "server_encoding") == 0)
		parse_server_encoding(args);
	else if (strcasecmp(name, "seed") == 0)
		parse_random_seed(args);
	else
	{
		/*
		 * For routines defined somewhere else, go ahead and extract the
		 * string argument to match the original interface definition.
		 * Later, we can change this code too...
		 */
		char	   *value;

		value = ((args != NULL) ? ((A_Const *) lfirst(args))->val.val.str : NULL);

		if (strcasecmp(name, "session_authorization") == 0)
			SetSessionAuthorization(value);
		else
			SetConfigOption(name, value, superuser() ? PGC_SUSET : PGC_USERSET, false);
	}
	return;
}

void
GetPGVariable(const char *name)
{
	if (strcasecmp(name, "datestyle") == 0)
		show_datestyle();
	else if (strcasecmp(name, "timezone") == 0)
		show_timezone();
	else if (strcasecmp(name, "XactIsoLevel") == 0)
		show_XactIsoLevel();
	else if (strcasecmp(name, "client_encoding") == 0)
		show_client_encoding();
	else if (strcasecmp(name, "server_encoding") == 0)
		show_server_encoding();
	else if (strcasecmp(name, "seed") == 0)
		show_random_seed();
	else if (strcasecmp(name, "all") == 0)
	{
		ShowAllGUCConfig();
		show_datestyle();
		show_timezone();
		show_XactIsoLevel();
		show_client_encoding();
		show_server_encoding();
		show_random_seed();
	}
	else
	{
		const char *val = GetConfigOption(name);

		elog(NOTICE, "%s is %s", name, val);
	}
}

void
ResetPGVariable(const char *name)
{
	if (strcasecmp(name, "datestyle") == 0)
		reset_datestyle();
	else if (strcasecmp(name, "timezone") == 0)
		reset_timezone();
	else if (strcasecmp(name, "XactIsoLevel") == 0)
		reset_XactIsoLevel();
	else if (strcasecmp(name, "client_encoding") == 0)
		reset_client_encoding();
	else if (strcasecmp(name, "server_encoding") == 0)
		reset_server_encoding();
	else if (strcasecmp(name, "seed") == 0)
		reset_random_seed();
	else if (strcasecmp(name, "all") == 0)
	{
		reset_random_seed();
		/* reset_server_encoding(); */
		reset_client_encoding();
		reset_datestyle();
		reset_timezone();

		ResetAllOptions(false);
	}
	else
		SetConfigOption(name, NULL,
						superuser() ? PGC_SUSET : PGC_USERSET,
						false);
}