]> granicus.if.org Git - postgresql/blob - src/backend/commands/variable.c
Allow varchar() to only store needed bytes. Remove PALLOC,PALLOCTYPE,PFREE. Clean...
[postgresql] / src / backend / commands / variable.c
1 /*
2  * Routines for handling of 'SET var TO',
3  *  'SHOW var' and 'RESET var' statements.
4  *
5  * $Id: variable.c,v 1.2 1998/01/07 18:46:26 momjian Exp $
6  *
7  */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <time.h>
13 #include "postgres.h"
14 #include "miscadmin.h"
15 #include "commands/variable.h"
16 #include "utils/builtins.h"
17 #include "optimizer/internal.h"
18
19 extern Cost _cpu_page_wight_;
20 extern Cost _cpu_index_page_wight_;
21 extern bool _use_geqo_;
22 extern int32 _use_geqo_rels_;
23 extern bool _use_right_sided_plans_;
24
25 /*-----------------------------------------------------------------------*/
26 #if USE_EURODATES
27 #define DATE_EURO               TRUE
28 #else
29 #define DATE_EURO FALSE
30 #endif
31
32 /*-----------------------------------------------------------------------*/
33 struct PGVariables PGVariables =
34 {
35         {DATE_EURO, Date_Postgres}
36 };
37
38 /*-----------------------------------------------------------------------*/
39 static const char *
40 get_token(char **tok, char **val, const char *str)
41 {
42         const char *start;
43         int                     len = 0;
44
45         *tok = NULL;
46         if (val != NULL)
47                 *val = NULL;
48
49         if (!(*str))
50                 return NULL;
51
52         /* skip white spaces */
53         while (isspace(*str))
54                 str++;
55         if (*str == ',' || *str == '=')
56                 elog(ERROR, "Syntax error near (%s): empty setting", str);
57
58         /* end of string? then return NULL */
59         if (!(*str))
60                 return NULL;
61
62         /* OK, at beginning of non-NULL string... */
63         start = str;
64
65         /*
66          * count chars in token until we hit white space or comma or '=' or
67          * end of string
68          */
69         while (*str && (!isspace(*str))
70                    && *str != ',' && *str != '=')
71         {
72                 str++;
73                 len++;
74         }
75
76         *tok = (char *) palloc(len + 1);
77         StrNCpy(*tok, start, len+1);
78
79         /* skip white spaces */
80         while (isspace(*str))
81                 str++;
82
83         /* end of string? */
84         if (!(*str))
85         {
86                 return (str);
87
88                 /* delimiter? */
89         }
90         else if (*str == ',')
91         {
92                 return (++str);
93
94         }
95         else if ((val == NULL) || (*str != '='))
96         {
97                 elog(ERROR, "Syntax error near (%s)", str);
98         };
99
100         str++;                                          /* '=': get value */
101         len = 0;
102
103         /* skip white spaces */
104         while (isspace(*str))
105                 str++;
106
107         if (*str == ',' || !(*str))
108                 elog(ERROR, "Syntax error near (=%s)", str);
109
110         start = str;
111
112         /*
113          * count chars in token's value until we hit white space or comma or
114          * end of string
115          */
116         while (*str && (!isspace(*str)) && *str != ',')
117         {
118                 str++;
119                 len++;
120         }
121
122         *val = (char *) palloc(len + 1);
123         StrNCpy(*val, start, len+1);
124
125         /* skip white spaces */
126         while (isspace(*str))
127                 str++;
128
129         if (!(*str))
130                 return (NULL);
131         if (*str == ',')
132                 return (++str);
133
134         elog(ERROR, "Syntax error near (%s)", str);
135
136         return str;
137 }
138
139 /*-----------------------------------------------------------------------*/
140 #if FALSE
141 static bool
142 parse_null(const char *value)
143 {
144         return TRUE;
145 }
146
147 static bool
148 show_null(const char *value)
149 {
150         return TRUE;
151 }
152
153 static bool
154 reset_null(const char *value)
155 {
156         return TRUE;
157 }
158 #endif
159
160 bool
161 parse_geqo(const char *value)
162 {
163         const char *rest;
164         char       *tok,
165                            *val;
166
167         if (value == NULL)
168         {
169                 reset_geqo();
170                 return TRUE;
171         }
172
173         rest = get_token(&tok, &val, value);
174         if (tok == NULL)
175                 elog(ERROR, "Value undefined");
176
177         if ((rest) && (*rest != '\0'))
178                 elog(ERROR, "Unable to parse '%s'", value);
179
180         if (strcasecmp(tok, "on") == 0)
181         {
182                 int32           geqo_rels = GEQO_RELS;
183
184                 if (val != NULL)
185                 {
186                         geqo_rels = pg_atoi(val, sizeof(int32), '\0');
187                         if (geqo_rels <= 1)
188                                 elog(ERROR, "Bad value for # of relations (%s)", val);
189                         pfree(val);
190                 }
191                 _use_geqo_ = true;
192                 _use_geqo_rels_ = geqo_rels;
193         }
194         else if (strcasecmp(tok, "off") == 0)
195         {
196                 if ((val != NULL) && (*val != '\0'))
197                         elog(ERROR, "%s does not allow a parameter", tok);
198                 _use_geqo_ = false;
199         }
200         else
201                 elog(ERROR, "Bad value for GEQO (%s)", value);
202
203         pfree(tok);
204         return TRUE;
205 }
206
207 bool
208 show_geqo()
209 {
210
211         if (_use_geqo_)
212                 elog(NOTICE, "GEQO is ON beginning with %d relations", _use_geqo_rels_);
213         else
214                 elog(NOTICE, "GEQO is OFF");
215         return TRUE;
216 }
217
218 bool
219 reset_geqo(void)
220 {
221
222 #ifdef GEQO
223         _use_geqo_ = true;
224 #else
225         _use_geqo_ = false;
226 #endif
227         _use_geqo_rels_ = GEQO_RELS;
228         return TRUE;
229 }
230
231 bool
232 parse_r_plans(const char *value)
233 {
234         if (value == NULL)
235         {
236                 reset_r_plans();
237                 return TRUE;
238         }
239
240         if (strcasecmp(value, "on") == 0)
241                 _use_right_sided_plans_ = true;
242         else if (strcasecmp(value, "off") == 0)
243                 _use_right_sided_plans_ = false;
244         else
245                 elog(ERROR, "Bad value for Right-sided Plans (%s)", value);
246
247         return TRUE;
248 }
249
250 bool
251 show_r_plans()
252 {
253
254         if (_use_right_sided_plans_)
255                 elog(NOTICE, "Right-sided Plans are ON");
256         else
257                 elog(NOTICE, "Right-sided Plans are OFF");
258         return TRUE;
259 }
260
261 bool
262 reset_r_plans()
263 {
264
265 #ifdef USE_RIGHT_SIDED_PLANS
266         _use_right_sided_plans_ = true;
267 #else
268         _use_right_sided_plans_ = false;
269 #endif
270         return TRUE;
271 }
272
273 bool
274 parse_cost_heap(const char *value)
275 {
276         float32         res;
277
278         if (value == NULL)
279         {
280                 reset_cost_heap();
281                 return TRUE;
282         }
283
284         res = float4in((char *) value);
285         _cpu_page_wight_ = *res;
286
287         return TRUE;
288 }
289
290 bool
291 show_cost_heap()
292 {
293
294         elog(NOTICE, "COST_HEAP is %f", _cpu_page_wight_);
295         return TRUE;
296 }
297
298 bool
299 reset_cost_heap()
300 {
301         _cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
302         return TRUE;
303 }
304
305 bool
306 parse_cost_index(const char *value)
307 {
308         float32         res;
309
310         if (value == NULL)
311         {
312                 reset_cost_index();
313                 return TRUE;
314         }
315
316         res = float4in((char *) value);
317         _cpu_index_page_wight_ = *res;
318
319         return TRUE;
320 }
321
322 bool
323 show_cost_index()
324 {
325
326         elog(NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_);
327         return TRUE;
328 }
329
330 bool
331 reset_cost_index()
332 {
333         _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
334         return TRUE;
335 }
336
337 bool
338 parse_date(const char *value)
339 {
340         char       *tok;
341         int                     dcnt = 0,
342                                 ecnt = 0;
343
344         if (value == NULL)
345         {
346                 reset_date();
347                 return TRUE;
348         }
349
350         while ((value = get_token(&tok, NULL, value)) != 0)
351         {
352                 /* Ugh. Somebody ought to write a table driven version -- mjl */
353
354                 if (!strcasecmp(tok, "ISO"))
355                 {
356                         DateStyle = USE_ISO_DATES;
357                         dcnt++;
358                 }
359                 else if (!strcasecmp(tok, "SQL"))
360                 {
361                         DateStyle = USE_SQL_DATES;
362                         dcnt++;
363                 }
364                 else if (!strcasecmp(tok, "POSTGRES"))
365                 {
366                         DateStyle = USE_POSTGRES_DATES;
367                         dcnt++;
368                 }
369                 else if (!strcasecmp(tok, "GERMAN"))
370                 {
371                         DateStyle = USE_GERMAN_DATES;
372                         dcnt++;
373                         EuroDates = TRUE;
374                         if ((ecnt > 0) && (! EuroDates)) ecnt++;
375                 }
376                 else if (!strncasecmp(tok, "EURO", 4))
377                 {
378                         EuroDates = TRUE;
379                         if ((dcnt <= 0) || (DateStyle != USE_GERMAN_DATES)) ecnt++;
380                 }
381                 else if ((!strcasecmp(tok, "US"))
382                                  || (!strncasecmp(tok, "NONEURO", 7)))
383                 {
384                         EuroDates = FALSE;
385                         if ((dcnt <= 0) || (DateStyle == USE_GERMAN_DATES)) ecnt++;
386                 }
387                 else if (!strcasecmp(tok, "DEFAULT"))
388                 {
389                         DateStyle = USE_POSTGRES_DATES;
390                         EuroDates = FALSE;
391                         ecnt++;
392                 }
393                 else
394                 {
395                         elog(ERROR, "Bad value for date style (%s)", tok);
396                 }
397                 pfree(tok);
398         }
399
400         if (dcnt > 1 || ecnt > 1)
401                 elog(NOTICE, "Conflicting settings for date");
402
403         return TRUE;
404 }
405
406 bool
407 show_date()
408 {
409         char            buf[64];
410
411         strcpy(buf, "DateStyle is ");
412         switch (DateStyle)
413         {
414                 case USE_ISO_DATES:
415                         strcat(buf, "ISO");
416                         break;
417                 case USE_SQL_DATES:
418                         strcat(buf, "SQL");
419                         break;
420                 case USE_GERMAN_DATES:
421                         strcat(buf, "German");
422                         break;
423                 default:
424                         strcat(buf, "Postgres");
425                         break;
426         };
427         strcat(buf, " with ");
428         strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)"));
429         strcat(buf, " conventions");
430
431         elog(NOTICE, buf, NULL);
432
433         return TRUE;
434 }
435
436 bool
437 reset_date()
438 {
439         DateStyle = USE_POSTGRES_DATES;
440         EuroDates = FALSE;
441
442         return TRUE;
443 }
444
445 /* Timezone support
446  * Working storage for strings is allocated with an arbitrary size of 64 bytes.
447  */
448
449 static char *defaultTZ = NULL;
450 static char TZvalue[64];
451 static char tzbuf[64];
452
453 /* parse_timezone()
454  * Handle SET TIME ZONE...
455  * Try to save existing TZ environment variable for later use in RESET TIME ZONE.
456  * - thomas 1997-11-10
457  */
458 bool
459 parse_timezone(const char *value)
460 {
461         char       *tok;
462
463         if (value == NULL)
464         {
465                 reset_timezone();
466                 return TRUE;
467         }
468
469         while ((value = get_token(&tok, NULL, value)) != 0)
470         {
471                 /* Not yet tried to save original value from environment? */
472                 if (defaultTZ == NULL)
473                 {
474                         /* found something? then save it for later */
475                         if (getenv("TZ") != NULL)
476                         {
477                                 defaultTZ = getenv("TZ");
478                                 if (defaultTZ == NULL)
479                                         defaultTZ = (char *) -1;
480                                 else
481                                         strcpy(TZvalue, defaultTZ);
482                         }
483                         /* found nothing so mark with an invalid pointer */
484                         else
485                         {
486                                 defaultTZ = (char *) -1;
487                         }
488                 }
489
490                 strcpy(tzbuf, "TZ=");
491                 strcat(tzbuf, tok);
492                 if (putenv(tzbuf) != 0)
493                         elog(ERROR, "Unable to set TZ environment variable to %s", tok);
494
495                 tzset();
496                 pfree(tok);
497         }
498
499         return TRUE;
500 } /* parse_timezone() */
501
502 bool
503 show_timezone()
504 {
505         char       *tz;
506
507         tz = getenv("TZ");
508
509         elog(NOTICE, "Time zone is %s", ((tz != NULL)? tz: "unknown"));
510
511         return TRUE;
512 } /* show_timezone() */
513
514 /* reset_timezone()
515  * Set TZ environment variable to original value.
516  * Note that if TZ was originally not set, TZ should be cleared.
517  * unsetenv() works fine, but is BSD, not POSIX, and is not available
518  * under Solaris, among others. Apparently putenv() called as below
519  * clears the process-specific environment variables.
520  * Other reasonable arguments to putenv() (e.g. "TZ=", "TZ", "") result
521  * in a core dump (under Linux anyway).
522  */
523 bool
524 reset_timezone()
525 {
526         if ((defaultTZ != NULL) && (defaultTZ != (char *) -1))
527         {
528                 strcpy(tzbuf, "TZ=");
529                 strcat(tzbuf, TZvalue);
530                 if (putenv(tzbuf) != 0)
531                         elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue);
532         }
533         else
534         {
535                 strcpy(tzbuf, "=");
536                 if (putenv(tzbuf) != 0)
537                         elog(ERROR, "Unable to clear TZ environment variable", NULL);
538         }
539         tzset();
540
541         return TRUE;
542 } /* reset_timezone() */
543
544 /*-----------------------------------------------------------------------*/
545 struct VariableParsers
546 {
547         const char *name;
548         bool            (*parser) (const char *);
549         bool            (*show) ();
550         bool            (*reset) ();
551 }                       VariableParsers[] =
552
553 {
554         {       "datestyle", parse_date, show_date, reset_date },
555         {       "timezone", parse_timezone, show_timezone, reset_timezone },
556         {       "cost_heap", parse_cost_heap, show_cost_heap, reset_cost_heap },
557         {       "cost_index", parse_cost_index, show_cost_index, reset_cost_index },
558         {       "geqo", parse_geqo, show_geqo, reset_geqo },
559         {       "r_plans", parse_r_plans, show_r_plans, reset_r_plans },
560         {       NULL, NULL, NULL, NULL }
561 };
562
563 /*-----------------------------------------------------------------------*/
564 bool
565 SetPGVariable(const char *name, const char *value)
566 {
567         struct VariableParsers *vp;
568
569         for (vp = VariableParsers; vp->name; vp++)
570         {
571                 if (!strcasecmp(vp->name, name))
572                         return (vp->parser) (value);
573         }
574
575         elog(NOTICE, "Unrecognized variable %s", name);
576
577         return TRUE;
578 }
579
580 /*-----------------------------------------------------------------------*/
581 bool
582 GetPGVariable(const char *name)
583 {
584         struct VariableParsers *vp;
585
586         for (vp = VariableParsers; vp->name; vp++)
587         {
588                 if (!strcasecmp(vp->name, name))
589                         return (vp->show) ();
590         }
591
592         elog(NOTICE, "Unrecognized variable %s", name);
593
594         return TRUE;
595 }
596
597 /*-----------------------------------------------------------------------*/
598 bool
599 ResetPGVariable(const char *name)
600 {
601         struct VariableParsers *vp;
602
603         for (vp = VariableParsers; vp->name; vp++)
604         {
605                 if (!strcasecmp(vp->name, name))
606                         return (vp->reset) ();
607         }
608
609         elog(NOTICE, "Unrecognized variable %s", name);
610
611         return TRUE;
612 }