OSDN Git Service

Change Copyright from PostgreSQL, Inc to PostgreSQL Global Development Group.
[pg-rex/syncrep.git] / src / backend / commands / define.c
1 /*-------------------------------------------------------------------------
2  *
3  * define.c
4  *
5  *        These routines execute some of the CREATE statements.  In an earlier
6  *        version of Postgres, these were "define" statements.
7  *
8  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  *        $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.51 2001/01/24 19:42:52 momjian Exp $
14  *
15  * DESCRIPTION
16  *        The "DefineFoo" routines take the parse tree and pick out the
17  *        appropriate arguments/flags, passing the results to the
18  *        corresponding "FooDefine" routines (in src/catalog) that do
19  *        the actual catalog-munging.  These routines also verify permission
20  *        of the user to execute the command.
21  *
22  * NOTES
23  *        These things must be defined and committed in the following order:
24  *              "create function":
25  *                              input/output, recv/send procedures
26  *              "create type":
27  *                              type
28  *              "create operator":
29  *                              operators
30  *
31  *              Most of the parse-tree manipulation routines are defined in
32  *              commands/manip.c.
33  *
34  *-------------------------------------------------------------------------
35  */
36 #include <ctype.h>
37 #include <math.h>
38
39 #include "postgres.h"
40
41 #include "access/heapam.h"
42 #include "catalog/catname.h"
43 #include "catalog/pg_aggregate.h"
44 #include "catalog/pg_language.h"
45 #include "catalog/pg_operator.h"
46 #include "catalog/pg_proc.h"
47 #include "catalog/pg_shadow.h"
48 #include "catalog/pg_type.h"
49 #include "commands/defrem.h"
50 #include "fmgr.h"
51 #include "optimizer/cost.h"
52 #include "parser/parse_expr.h"
53 #include "tcop/dest.h"
54 #include "utils/builtins.h"
55 #include "utils/syscache.h"
56
57 static char *defGetString(DefElem *def);
58 static double defGetNumeric(DefElem *def);
59 static int      defGetTypeLength(DefElem *def);
60
61 #define DEFAULT_TYPDELIM                ','
62
63
64 static void
65 case_translate_language_name(const char *input, char *output)
66 {
67 /*-------------------------------------------------------------------------
68   Translate the input language name to lower case, except if it's "C",
69   translate to upper case.
70 --------------------------------------------------------------------------*/
71         int                     i;
72
73         for (i = 0; i < NAMEDATALEN-1 && input[i]; ++i)
74                 output[i] = tolower((unsigned char) input[i]);
75
76         output[i] = '\0';
77
78         if (strcmp(output, "c") == 0)
79                 output[0] = 'C';
80 }
81
82
83
84 static void
85 compute_return_type(TypeName *returnType,
86                                         char **prorettype_p, bool *returnsSet_p)
87 {
88 /*---------------------------------------------------------------------------
89    Examine the "returns" clause returnType of the CREATE FUNCTION statement
90    and return information about it as *prorettype_p and *returnsSet.
91 ----------------------------------------------------------------------------*/
92         *prorettype_p = TypeNameToInternalName(returnType);
93         *returnsSet_p = returnType->setof;
94 }
95
96
97 static void
98 compute_full_attributes(List *parameters,
99                                                 int32 *byte_pct_p, int32 *perbyte_cpu_p,
100                                                 int32 *percall_cpu_p, int32 *outin_ratio_p,
101                                                 bool *canCache_p, bool *isStrict_p)
102 {
103 /*--------------------------------------------------------------------------
104   Interpret the parameters *parameters and return their contents as
105   *byte_pct_p, etc.
106
107   These parameters supply optional information about a function.
108   All have defaults if not specified.
109
110   Note: currently, only two of these parameters actually do anything:
111
112   * canCache means the optimizer's constant-folder is allowed to
113     pre-evaluate the function when all its inputs are constants.
114
115   * isStrict means the function should not be called when any NULL
116     inputs are present; instead a NULL result value should be assumed.
117
118   The other four parameters are not used anywhere.  They used to be
119   used in the "expensive functions" optimizer, but that's been dead code
120   for a long time.
121
122   Since canCache and isStrict are useful for any function, we now allow
123   attributes to be supplied for all functions regardless of language.
124 ---------------------------------------------------------------------------*/
125         List       *pl;
126
127         /* the defaults */
128         *byte_pct_p = BYTE_PCT;
129         *perbyte_cpu_p = PERBYTE_CPU;
130         *percall_cpu_p = PERCALL_CPU;
131         *outin_ratio_p = OUTIN_RATIO;
132         *canCache_p = false;
133         *isStrict_p = false;
134
135         foreach(pl, parameters)
136         {
137                 DefElem    *param = (DefElem *) lfirst(pl);
138
139                 if (strcasecmp(param->defname, "iscachable") == 0)
140                         *canCache_p = true;
141                 else if (strcasecmp(param->defname, "isstrict") == 0)
142                         *isStrict_p = true;
143                 else if (strcasecmp(param->defname, "trusted") == 0)
144                 {
145
146                         /*
147                          * we don't have untrusted functions any more. The 4.2
148                          * implementation is lousy anyway so I took it out. -ay 10/94
149                          */
150                         elog(ERROR, "untrusted function has been decommissioned.");
151                 }
152                 else if (strcasecmp(param->defname, "byte_pct") == 0)
153                         *byte_pct_p = (int) defGetNumeric(param);
154                 else if (strcasecmp(param->defname, "perbyte_cpu") == 0)
155                         *perbyte_cpu_p = (int) defGetNumeric(param);
156                 else if (strcasecmp(param->defname, "percall_cpu") == 0)
157                         *percall_cpu_p = (int) defGetNumeric(param);
158                 else if (strcasecmp(param->defname, "outin_ratio") == 0)
159                         *outin_ratio_p = (int) defGetNumeric(param);
160                 else
161                         elog(NOTICE, "Unrecognized function attribute '%s' ignored",
162                                  param->defname);
163         }
164 }
165
166
167 /*
168  * For a dynamically linked C language object, the form of the clause is
169  *
170  *         AS <object file name> [, <link symbol name> ]
171  *
172  * In all other cases
173  *
174  *         AS <object reference, or sql code>
175  *
176  */
177
178 static void
179 interpret_AS_clause(const char *languageName, const List *as,
180                                         char **prosrc_str_p, char **probin_str_p)
181 {
182         Assert(as != NIL);
183
184         if (strcmp(languageName, "C") == 0)
185         {
186
187                 /*
188                  * For "C" language, store the file name in probin and, when
189                  * given, the link symbol name in prosrc.
190                  */
191                 *probin_str_p = strVal(lfirst(as));
192                 if (lnext(as) == NULL)
193                         *prosrc_str_p = "-";
194                 else
195                         *prosrc_str_p = strVal(lsecond(as));
196         }
197         else
198         {
199                 /* Everything else wants the given string in prosrc. */
200                 *prosrc_str_p = strVal(lfirst(as));
201                 *probin_str_p = "-";
202
203                 if (lnext(as) != NIL)
204                         elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language",
205                                  languageName);
206         }
207 }
208
209
210
211 /*
212  * CreateFunction
213  *       Execute a CREATE FUNCTION utility statement.
214  *
215  */
216 void
217 CreateFunction(ProcedureStmt *stmt, CommandDest dest)
218 {
219         char       *probin_str;
220         /* pathname of executable file that executes this function, if any */
221
222         char       *prosrc_str;
223         /* SQL that executes this function, if any */
224
225         char       *prorettype;
226         /* Type of return value (or member of set of values) from function */
227
228         char            languageName[NAMEDATALEN];
229         /*
230          * name of language of function, with case adjusted: "C",
231          * "internal", "sql", etc.
232          */
233
234         bool            returnsSet;
235         /* The function returns a set of values, as opposed to a singleton. */
236
237         /*
238          * The following are optional user-supplied attributes of the
239          * function.
240          */
241         int32           byte_pct,
242                                 perbyte_cpu,
243                                 percall_cpu,
244                                 outin_ratio;
245         bool            canCache,
246                                 isStrict;
247
248         /* Convert language name to canonical case */
249         case_translate_language_name(stmt->language, languageName);
250
251         /*
252          * Apply appropriate security checks depending on language.
253          */
254         if (strcmp(languageName, "C") == 0 ||
255                 strcmp(languageName, "internal") == 0)
256         {
257                 if (!superuser())
258                         elog(ERROR,
259                                  "Only users with Postgres superuser privilege are "
260                                  "permitted to create a function in the '%s' language.\n\t"
261                                  "Others may use the 'sql' language "
262                                  "or the created procedural languages.",
263                                  languageName);
264         }
265         else if (strcmp(languageName, "sql") == 0)
266         {
267                 /* No security check needed for SQL functions */
268         }
269         else
270         {
271                 HeapTuple       languageTuple;
272                 Form_pg_language languageStruct;
273
274                 /* Lookup the language in the system cache */
275                 languageTuple = SearchSysCache(LANGNAME,
276                                                                            PointerGetDatum(languageName),
277                                                                            0, 0, 0);
278                 if (!HeapTupleIsValid(languageTuple))
279                         elog(ERROR,
280                                  "Unrecognized language specified in a CREATE FUNCTION: "
281                                  "'%s'.\n\tRecognized languages are sql, C, "
282                                  "internal, and created procedural languages.",
283                                  languageName);
284
285                 /* Check that this language is a PL */
286                 languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
287                 if (!languageStruct->lanispl)
288                         elog(ERROR,
289                                  "Language '%s' isn't defined as PL", languageName);
290
291                 /*
292                  * Functions in untrusted procedural languages are restricted to
293                  * be defined by postgres superusers only
294                  */
295                 if (!languageStruct->lanpltrusted && !superuser())
296                         elog(ERROR, "Only users with Postgres superuser privilege "
297                                  "are permitted to create a function in the '%s' "
298                                  "language.",
299                                  languageName);
300
301                 ReleaseSysCache(languageTuple);
302         }
303
304         /*
305          * Convert remaining parameters of CREATE to form wanted by
306          * ProcedureCreate.
307          */
308         Assert(IsA(stmt->returnType, TypeName));
309         compute_return_type((TypeName *) stmt->returnType,
310                                                 &prorettype, &returnsSet);
311
312         compute_full_attributes(stmt->withClause,
313                                                         &byte_pct, &perbyte_cpu, &percall_cpu,
314                                                         &outin_ratio, &canCache, &isStrict);
315
316         interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
317
318         /*
319          * And now that we have all the parameters, and know we're permitted
320          * to do so, go ahead and create the function.
321          */
322         ProcedureCreate(stmt->funcname,
323                                         returnsSet,
324                                         prorettype,
325                                         languageName,
326                                         prosrc_str, /* converted to text later */
327                                         probin_str, /* converted to text later */
328                                         true,           /* (obsolete "trusted") */
329                                         canCache,
330                                         isStrict,
331                                         byte_pct,
332                                         perbyte_cpu,
333                                         percall_cpu,
334                                         outin_ratio,
335                                         stmt->argTypes,
336                                         dest);
337 }
338
339
340
341 /* --------------------------------
342  * DefineOperator
343  *
344  *              this function extracts all the information from the
345  *              parameter list generated by the parser and then has
346  *              OperatorCreate() do all the actual work.
347  *
348  * 'parameters' is a list of DefElem
349  * --------------------------------
350  */
351 void
352 DefineOperator(char *oprName,
353                            List *parameters)
354 {
355         uint16          precedence = 0; /* operator precedence */
356         bool            canHash = false;/* operator hashes */
357         bool            isLeftAssociative = true;               /* operator is left
358                                                                                                  * associative */
359         char       *functionName = NULL;        /* function for operator */
360         char       *typeName1 = NULL;           /* first type name */
361         char       *typeName2 = NULL;           /* second type name */
362         char       *commutatorName = NULL;      /* optional commutator operator
363                                                                                  * name */
364         char       *negatorName = NULL;         /* optional negator operator name */
365         char       *restrictionName = NULL; /* optional restrict. sel.
366                                                                                  * procedure */
367         char       *joinName = NULL;/* optional join sel. procedure name */
368         char       *sortName1 = NULL;           /* optional first sort operator */
369         char       *sortName2 = NULL;           /* optional second sort operator */
370         List       *pl;
371
372         /*
373          * loop over the definition list and extract the information we need.
374          */
375         foreach(pl, parameters)
376         {
377                 DefElem    *defel = (DefElem *) lfirst(pl);
378
379                 if (strcasecmp(defel->defname, "leftarg") == 0)
380                 {
381                         typeName1 = defGetString(defel);
382                         if (IsA(defel->arg, TypeName)
383                                 && ((TypeName *) defel->arg)->setof)
384                                 elog(ERROR, "setof type not implemented for leftarg");
385                 }
386                 else if (strcasecmp(defel->defname, "rightarg") == 0)
387                 {
388                         typeName2 = defGetString(defel);
389                         if (IsA(defel->arg, TypeName)
390                                 && ((TypeName *) defel->arg)->setof)
391                                 elog(ERROR, "setof type not implemented for rightarg");
392                 }
393                 else if (strcasecmp(defel->defname, "procedure") == 0)
394                         functionName = defGetString(defel);
395                 else if (strcasecmp(defel->defname, "precedence") == 0)
396                 {
397                         /* NOT IMPLEMENTED (never worked in v4.2) */
398                         elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
399                 }
400                 else if (strcasecmp(defel->defname, "associativity") == 0)
401                 {
402                         /* NOT IMPLEMENTED (never worked in v4.2) */
403                         elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
404                 }
405                 else if (strcasecmp(defel->defname, "commutator") == 0)
406                         commutatorName = defGetString(defel);
407                 else if (strcasecmp(defel->defname, "negator") == 0)
408                         negatorName = defGetString(defel);
409                 else if (strcasecmp(defel->defname, "restrict") == 0)
410                         restrictionName = defGetString(defel);
411                 else if (strcasecmp(defel->defname, "join") == 0)
412                         joinName = defGetString(defel);
413                 else if (strcasecmp(defel->defname, "hashes") == 0)
414                         canHash = TRUE;
415                 else if (strcasecmp(defel->defname, "sort1") == 0)
416                 {
417                         /* ----------------
418                          * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
419                          * XXX is undocumented in the reference manual source as of
420                          * 89/8/22.
421                          * ----------------
422                          */
423                         sortName1 = defGetString(defel);
424                 }
425                 else if (strcasecmp(defel->defname, "sort2") == 0)
426                         sortName2 = defGetString(defel);
427                 else
428                 {
429                         elog(NOTICE, "DefineOperator: attribute \"%s\" not recognized",
430                                  defel->defname);
431                 }
432         }
433
434         /*
435          * make sure we have our required definitions
436          */
437         if (functionName == NULL)
438                 elog(ERROR, "Define: \"procedure\" unspecified");
439
440         /* ----------------
441          *      now have OperatorCreate do all the work..
442          * ----------------
443          */
444         OperatorCreate(oprName,         /* operator name */
445                                    typeName1,   /* first type name */
446                                    typeName2,   /* second type name */
447                                    functionName,/* function for operator */
448                                    precedence,  /* operator precedence */
449                                    isLeftAssociative,   /* operator is left associative */
450                                    commutatorName,              /* optional commutator operator
451                                                                                  * name */
452                                    negatorName, /* optional negator operator name */
453                                    restrictionName,             /* optional restrict. sel.
454                                                                                  * procedure */
455                                    joinName,    /* optional join sel. procedure name */
456                                    canHash,             /* operator hashes */
457                                    sortName1,   /* optional first sort operator */
458                                    sortName2);  /* optional second sort operator */
459
460 }
461
462 /* -------------------
463  *      DefineAggregate
464  * ------------------
465  */
466 void
467 DefineAggregate(char *aggName, List *parameters)
468 {
469         char       *transfuncName = NULL;
470         char       *finalfuncName = NULL;
471         char       *baseType = NULL;
472         char       *transType = NULL;
473         char       *initval = NULL;
474         List       *pl;
475
476         foreach(pl, parameters)
477         {
478                 DefElem    *defel = (DefElem *) lfirst(pl);
479
480                 /*
481                  * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
482                  * for sfunc, stype, initcond.
483                  */
484                 if (strcasecmp(defel->defname, "sfunc") == 0)
485                         transfuncName = defGetString(defel);
486                 else if (strcasecmp(defel->defname, "sfunc1") == 0)
487                         transfuncName = defGetString(defel);
488                 else if (strcasecmp(defel->defname, "finalfunc") == 0)
489                         finalfuncName = defGetString(defel);
490                 else if (strcasecmp(defel->defname, "basetype") == 0)
491                         baseType = defGetString(defel);
492                 else if (strcasecmp(defel->defname, "stype") == 0)
493                         transType = defGetString(defel);
494                 else if (strcasecmp(defel->defname, "stype1") == 0)
495                         transType = defGetString(defel);
496                 else if (strcasecmp(defel->defname, "initcond") == 0)
497                         initval = defGetString(defel);
498                 else if (strcasecmp(defel->defname, "initcond1") == 0)
499                         initval = defGetString(defel);
500                 else
501                         elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
502                                  defel->defname);
503         }
504
505         /*
506          * make sure we have our required definitions
507          */
508         if (baseType == NULL)
509                 elog(ERROR, "Define: \"basetype\" unspecified");
510         if (transType == NULL)
511                 elog(ERROR, "Define: \"stype\" unspecified");
512         if (transfuncName == NULL)
513                 elog(ERROR, "Define: \"sfunc\" unspecified");
514
515         /*
516          * Most of the argument-checking is done inside of AggregateCreate
517          */
518         AggregateCreate(aggName,                /* aggregate name */
519                                         transfuncName,  /* step function name */
520                                         finalfuncName,  /* final function name */
521                                         baseType,               /* type of data being aggregated */
522                                         transType,              /* transition data type */
523                                         initval);               /* initial condition */
524 }
525
526 /*
527  * DefineType
528  *              Registers a new type.
529  *
530  */
531 void
532 DefineType(char *typeName, List *parameters)
533 {
534         int16           internalLength = 0;             /* int2 */
535         int16           externalLength = 0;             /* int2 */
536         char       *elemName = NULL;
537         char       *inputName = NULL;
538         char       *outputName = NULL;
539         char       *sendName = NULL;
540         char       *receiveName = NULL;
541         char       *defaultValue = NULL;        /* Datum */
542         bool            byValue = false;
543         char            delimiter = DEFAULT_TYPDELIM;
544         char       *shadow_type;
545         List       *pl;
546         char            alignment = 'i'; /* default alignment */
547         char            storage = 'p';  /* default storage in TOAST */
548
549         /*
550          * Type names must be one character shorter than other names,
551          * allowing room to create the corresponding array type name with
552          * prepended "_".
553          */
554         if (strlen(typeName) > (NAMEDATALEN - 2))
555         {
556                 elog(ERROR, "DefineType: type names must be %d characters or less",
557                          NAMEDATALEN - 2);
558         }
559
560         foreach(pl, parameters)
561         {
562                 DefElem    *defel = (DefElem *) lfirst(pl);
563
564                 if (strcasecmp(defel->defname, "internallength") == 0)
565                         internalLength = defGetTypeLength(defel);
566                 else if (strcasecmp(defel->defname, "externallength") == 0)
567                         externalLength = defGetTypeLength(defel);
568                 else if (strcasecmp(defel->defname, "input") == 0)
569                         inputName = defGetString(defel);
570                 else if (strcasecmp(defel->defname, "output") == 0)
571                         outputName = defGetString(defel);
572                 else if (strcasecmp(defel->defname, "send") == 0)
573                         sendName = defGetString(defel);
574                 else if (strcasecmp(defel->defname, "delimiter") == 0)
575                 {
576                         char       *p = defGetString(defel);
577
578                         delimiter = p[0];
579                 }
580                 else if (strcasecmp(defel->defname, "receive") == 0)
581                         receiveName = defGetString(defel);
582                 else if (strcasecmp(defel->defname, "element") == 0)
583                         elemName = defGetString(defel);
584                 else if (strcasecmp(defel->defname, "default") == 0)
585                         defaultValue = defGetString(defel);
586                 else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
587                         byValue = true;
588                 else if (strcasecmp(defel->defname, "alignment") == 0)
589                 {
590                         char       *a = defGetString(defel);
591
592                         if (strcasecmp(a, "double") == 0)
593                                 alignment = 'd';
594                         else if (strcasecmp(a, "int4") == 0)
595                                 alignment = 'i';
596                         else
597                         {
598                                 elog(ERROR, "DefineType: \"%s\" alignment not recognized",
599                                          a);
600                         }
601                 }
602                 else if (strcasecmp(defel->defname, "storage") == 0)
603                 {
604                         char       *a = defGetString(defel);
605
606                         if (strcasecmp(a, "plain") == 0)
607                                 storage = 'p';
608                         else if (strcasecmp(a, "external") == 0)
609                                 storage = 'e';
610                         else if (strcasecmp(a, "extended") == 0)
611                                 storage = 'x';
612                         else if (strcasecmp(a, "main") == 0)
613                                 storage = 'm';
614                         else
615                         {
616                                 elog(ERROR, "DefineType: \"%s\" storage not recognized",
617                                          a);
618                         }
619                 }
620                 else
621                 {
622                         elog(NOTICE, "DefineType: attribute \"%s\" not recognized",
623                                  defel->defname);
624                 }
625         }
626
627         /*
628          * make sure we have our required definitions
629          */
630         if (inputName == NULL)
631                 elog(ERROR, "Define: \"input\" unspecified");
632         if (outputName == NULL)
633                 elog(ERROR, "Define: \"output\" unspecified");
634
635         if (internalLength != -1 && storage != 'p')
636                 elog(ERROR, "Define: fixed size types must have storage PLAIN");
637
638         /* ----------------
639          *      now have TypeCreate do all the real work.
640          * ----------------
641          */
642         TypeCreate(typeName,            /* type name */
643                            InvalidOid,          /* relation oid (n/a here) */
644                            internalLength,      /* internal size */
645                            externalLength,      /* external size */
646                            'b',                         /* type-type (base type) */
647                            delimiter,           /* array element delimiter */
648                            inputName,           /* input procedure */
649                            outputName,          /* output procedure */
650                            receiveName,         /* receive procedure */
651                            sendName,            /* send procedure */
652                            elemName,            /* element type name */
653                            defaultValue,        /* default type value */
654                            byValue,                     /* passed by value */
655                            alignment,
656                            storage);            /* TOAST strategy */
657
658         /* ----------------
659          *      When we create a base type (as opposed to a complex type)
660          *      we need to have an array entry for it in pg_type as well.
661          * ----------------
662          */
663         shadow_type = makeArrayTypeName(typeName);
664
665         TypeCreate(shadow_type,         /* type name */
666                            InvalidOid,          /* relation oid (n/a here) */
667                            -1,                          /* internal size */
668                            -1,                          /* external size */
669                            'b',                         /* type-type (base type) */
670                            DEFAULT_TYPDELIM,/* array element delimiter */
671                            "array_in",          /* input procedure */
672                            "array_out",         /* output procedure */
673                            "array_in",          /* receive procedure */
674                            "array_out",         /* send procedure */
675                            typeName,            /* element type name */
676                            NULL,                        /* never a default type value */
677                            false,                       /* never passed by value */
678                            alignment,           /* NB: must be 'i' or 'd' for arrays... */
679                            'x');                        /* ARRAY is always toastable */
680
681         pfree(shadow_type);
682 }
683
684 static char *
685 defGetString(DefElem *def)
686 {
687         if (def->arg == NULL)
688                 elog(ERROR, "Define: \"%s\" requires a parameter",
689                          def->defname);
690         switch (nodeTag(def->arg))
691         {
692                 case T_Integer:
693                 {
694                         char *str = palloc(32);
695
696                         snprintf(str, 32, "%ld", (long) intVal(def->arg));
697                         return str;
698                 }
699                 case T_Float:
700                         /* T_Float values are kept in string form, so this type cheat
701                          * works (and doesn't risk losing precision)
702                          */
703                         return strVal(def->arg);
704                 case T_String:
705                         return strVal(def->arg);
706                 case T_TypeName:
707                         return TypeNameToInternalName((TypeName *) def->arg);
708                 default:
709                         elog(ERROR, "Define: cannot interpret argument of \"%s\"",
710                                  def->defname);
711         }
712         return NULL;                            /* keep compiler quiet */
713 }
714
715 static double
716 defGetNumeric(DefElem *def)
717 {
718         if (def->arg == NULL)
719                 elog(ERROR, "Define: \"%s\" requires a numeric value",
720                          def->defname);
721         switch (nodeTag(def->arg))
722         {
723                 case T_Integer:
724                         return (double) intVal(def->arg);
725                 case T_Float:
726                         return floatVal(def->arg);
727                 default:
728                         elog(ERROR, "Define: \"%s\" requires a numeric value",
729                                  def->defname);
730         }
731         return 0;                                       /* keep compiler quiet */
732 }
733
734 static int
735 defGetTypeLength(DefElem *def)
736 {
737         if (def->arg == NULL)
738                 elog(ERROR, "Define: \"%s\" requires a parameter",
739                          def->defname);
740         switch (nodeTag(def->arg))
741         {
742                 case T_Integer:
743                         return intVal(def->arg);
744                 case T_Float:
745                         elog(ERROR, "Define: \"%s\" requires an integral value",
746                                  def->defname);
747                         break;
748                 case T_String:
749                         if (strcasecmp(strVal(def->arg), "variable") == 0)
750                                 return -1;              /* variable length */
751                         break;
752                 case T_TypeName:
753                         /* cope if grammar chooses to believe "variable" is a typename */
754                         if (strcasecmp(TypeNameToInternalName((TypeName *) def->arg),
755                                                    "variable") == 0)
756                                 return -1;              /* variable length */
757                         break;
758                 default:
759                         elog(ERROR, "Define: cannot interpret argument of \"%s\"",
760                                  def->defname);
761         }
762         elog(ERROR, "Define: invalid argument for \"%s\"",
763                  def->defname);
764         return 0;                                       /* keep compiler quiet */
765 }