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