diff options
Diffstat (limited to 'src/backend/commands/define.c')
-rw-r--r-- | src/backend/commands/define.c | 226 |
1 files changed, 122 insertions, 104 deletions
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index cf31e5edb1f..a33d155db9f 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.46 2000/07/22 03:34:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.47 2000/10/07 00:58:16 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -49,6 +49,7 @@ #include "commands/defrem.h" #include "fmgr.h" #include "optimizer/cost.h" +#include "parser/parse_expr.h" #include "tcop/dest.h" #include "utils/builtins.h" #include "utils/syscache.h" @@ -83,27 +84,15 @@ case_translate_language_name(const char *input, char *output) static void -compute_return_type(const Node *returnType, +compute_return_type(TypeName *returnType, char **prorettype_p, bool *returnsSet_p) { /*--------------------------------------------------------------------------- Examine the "returns" clause returnType of the CREATE FUNCTION statement - and return information about it as **prorettype_p and **returnsSet. + and return information about it as *prorettype_p and *returnsSet. ----------------------------------------------------------------------------*/ - if (nodeTag(returnType) == T_TypeName) - { - /* a set of values */ - TypeName *setType = (TypeName *) returnType; - - *prorettype_p = setType->name; - *returnsSet_p = setType->setof; - } - else - { - /* singleton */ - *prorettype_p = strVal(returnType); - *returnsSet_p = false; - } + *prorettype_p = TypeNameToInternalName(returnType); + *returnsSet_p = returnType->setof; } @@ -214,7 +203,7 @@ interpret_AS_clause(const char *languageName, const List *as, *prosrc_str_p = strVal(lfirst(as)); *probin_str_p = "-"; - if (lnext(as) != NULL) + if (lnext(as) != NIL) elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language", languageName); } @@ -231,27 +220,23 @@ void CreateFunction(ProcedureStmt *stmt, CommandDest dest) { char *probin_str; - /* pathname of executable file that executes this function, if any */ - char *prosrc_str; + char *prosrc_str; /* SQL that executes this function, if any */ - char *prorettype; + char *prorettype; /* Type of return value (or member of set of values) from function */ - char languageName[NAMEDATALEN]; + char languageName[NAMEDATALEN]; /* * name of language of function, with case adjusted: "C", "newC", * "internal", "newinternal", "sql", etc. */ bool returnsSet; - /* The function returns a set of values, as opposed to a singleton. */ - bool lanisPL = false; - /* * The following are optional user-supplied attributes of the * function. @@ -263,8 +248,12 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) bool canCache, isStrict; + /* Convert language name to canonical case */ case_translate_language_name(stmt->language, languageName); + /* + * Apply appropriate security checks depending on language. + */ if (strcmp(languageName, "C") == 0 || strcmp(languageName, "newC") == 0 || strcmp(languageName, "internal") == 0 || @@ -301,7 +290,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) /* Check that this language is a PL */ languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); - if (!(languageStruct->lanispl)) + if (!languageStruct->lanispl) elog(ERROR, "Language '%s' isn't defined as PL", languageName); @@ -316,11 +305,15 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) "language.", languageName); } - - lanisPL = true; } - compute_return_type(stmt->returnType, &prorettype, &returnsSet); + /* + * Convert remaining parameters of CREATE to form wanted by + * ProcedureCreate. + */ + Assert(IsA(stmt->returnType, TypeName)); + compute_return_type((TypeName *) stmt->returnType, + &prorettype, &returnsSet); compute_full_attributes(stmt->withClause, &byte_pct, &perbyte_cpu, &percall_cpu, @@ -345,7 +338,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) perbyte_cpu, percall_cpu, outin_ratio, - stmt->defArgs, + stmt->argTypes, dest); } @@ -389,49 +382,43 @@ DefineOperator(char *oprName, { DefElem *defel = (DefElem *) lfirst(pl); - if (!strcasecmp(defel->defname, "leftarg")) + if (strcasecmp(defel->defname, "leftarg") == 0) { - if ((nodeTag(defel->arg) == T_TypeName) - && (((TypeName *) defel->arg)->setof)) - elog(ERROR, "setof type not implemented for leftarg"); - typeName1 = defGetString(defel); - if (typeName1 == NULL) - elog(ERROR, "type for leftarg is malformed."); + if (IsA(defel->arg, TypeName) + && ((TypeName *) defel->arg)->setof) + elog(ERROR, "setof type not implemented for leftarg"); } - else if (!strcasecmp(defel->defname, "rightarg")) + else if (strcasecmp(defel->defname, "rightarg") == 0) { - if ((nodeTag(defel->arg) == T_TypeName) - && (((TypeName *) defel->arg)->setof)) - elog(ERROR, "setof type not implemented for rightarg"); - typeName2 = defGetString(defel); - if (typeName2 == NULL) - elog(ERROR, "type for rightarg is malformed."); + if (IsA(defel->arg, TypeName) + && ((TypeName *) defel->arg)->setof) + elog(ERROR, "setof type not implemented for rightarg"); } - else if (!strcasecmp(defel->defname, "procedure")) + else if (strcasecmp(defel->defname, "procedure") == 0) functionName = defGetString(defel); - else if (!strcasecmp(defel->defname, "precedence")) + else if (strcasecmp(defel->defname, "precedence") == 0) { /* NOT IMPLEMENTED (never worked in v4.2) */ elog(NOTICE, "CREATE OPERATOR: precedence not implemented"); } - else if (!strcasecmp(defel->defname, "associativity")) + else if (strcasecmp(defel->defname, "associativity") == 0) { /* NOT IMPLEMENTED (never worked in v4.2) */ elog(NOTICE, "CREATE OPERATOR: associativity not implemented"); } - else if (!strcasecmp(defel->defname, "commutator")) + else if (strcasecmp(defel->defname, "commutator") == 0) commutatorName = defGetString(defel); - else if (!strcasecmp(defel->defname, "negator")) + else if (strcasecmp(defel->defname, "negator") == 0) negatorName = defGetString(defel); - else if (!strcasecmp(defel->defname, "restrict")) + else if (strcasecmp(defel->defname, "restrict") == 0) restrictionName = defGetString(defel); - else if (!strcasecmp(defel->defname, "join")) + else if (strcasecmp(defel->defname, "join") == 0) joinName = defGetString(defel); - else if (!strcasecmp(defel->defname, "hashes")) + else if (strcasecmp(defel->defname, "hashes") == 0) canHash = TRUE; - else if (!strcasecmp(defel->defname, "sort1")) + else if (strcasecmp(defel->defname, "sort1") == 0) { /* ---------------- * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... ) @@ -441,7 +428,7 @@ DefineOperator(char *oprName, */ sortName1 = defGetString(defel); } - else if (!strcasecmp(defel->defname, "sort2")) + else if (strcasecmp(defel->defname, "sort2") == 0) sortName2 = defGetString(defel); else { @@ -562,72 +549,73 @@ DefineType(char *typeName, List *parameters) char delimiter = DEFAULT_TYPDELIM; char *shadow_type; List *pl; - char alignment = 'i';/* default alignment */ - char storage = 'p'; /* default storage in TOAST */ + char alignment = 'i'; /* default alignment */ + char storage = 'p'; /* default storage in TOAST */ /* - * Type names can only be 15 characters long, so that the shadow type - * can be created using the 16th character as necessary. + * Type names must be one character shorter than other names, + * allowing room to create the corresponding array type name with + * prepended "_". */ - if (strlen(typeName) >= (NAMEDATALEN - 1)) + if (strlen(typeName) > (NAMEDATALEN - 2)) { elog(ERROR, "DefineType: type names must be %d characters or less", - NAMEDATALEN - 1); + NAMEDATALEN - 2); } foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); - if (!strcasecmp(defel->defname, "internallength")) + if (strcasecmp(defel->defname, "internallength") == 0) internalLength = defGetTypeLength(defel); - else if (!strcasecmp(defel->defname, "externallength")) + else if (strcasecmp(defel->defname, "externallength") == 0) externalLength = defGetTypeLength(defel); - else if (!strcasecmp(defel->defname, "input")) + else if (strcasecmp(defel->defname, "input") == 0) inputName = defGetString(defel); - else if (!strcasecmp(defel->defname, "output")) + else if (strcasecmp(defel->defname, "output") == 0) outputName = defGetString(defel); - else if (!strcasecmp(defel->defname, "send")) + else if (strcasecmp(defel->defname, "send") == 0) sendName = defGetString(defel); - else if (!strcasecmp(defel->defname, "delimiter")) + else if (strcasecmp(defel->defname, "delimiter") == 0) { char *p = defGetString(defel); delimiter = p[0]; } - else if (!strcasecmp(defel->defname, "receive")) + else if (strcasecmp(defel->defname, "receive") == 0) receiveName = defGetString(defel); - else if (!strcasecmp(defel->defname, "element")) + else if (strcasecmp(defel->defname, "element") == 0) elemName = defGetString(defel); - else if (!strcasecmp(defel->defname, "default")) + else if (strcasecmp(defel->defname, "default") == 0) defaultValue = defGetString(defel); - else if (!strcasecmp(defel->defname, "passedbyvalue")) + else if (strcasecmp(defel->defname, "passedbyvalue") == 0) byValue = true; - else if (!strcasecmp(defel->defname, "alignment")) + else if (strcasecmp(defel->defname, "alignment") == 0) { char *a = defGetString(defel); - if (!strcasecmp(a, "double")) + if (strcasecmp(a, "double") == 0) alignment = 'd'; - else if (!strcasecmp(a, "int4")) + else if (strcasecmp(a, "int4") == 0) alignment = 'i'; else { - elog(ERROR, "DefineType: \"%s\" alignment not recognized", + elog(ERROR, "DefineType: \"%s\" alignment not recognized", a); } } - else if (!strcasecmp(defel->defname, "storage")) + else if (strcasecmp(defel->defname, "storage") == 0) { char *a = defGetString(defel); - if (!strcasecmp(a, "plain")) + if (strcasecmp(a, "plain") == 0) storage = 'p'; - else if (!strcasecmp(a, "external")) + else if (strcasecmp(a, "external") == 0) storage = 'e'; - else if (!strcasecmp(a, "extended")) + else if (strcasecmp(a, "extended") == 0) storage = 'x'; - else if (!strcasecmp(a, "main")) + else if (strcasecmp(a, "main") == 0) storage = 'm'; else { @@ -674,8 +662,8 @@ DefineType(char *typeName, List *parameters) storage); /* TOAST strategy */ /* ---------------- - * When we create a true type (as opposed to a complex type) - * we need to have an shadow array entry for it in pg_type as well. + * When we create a base type (as opposed to a complex type) + * we need to have an array entry for it in pg_type as well. * ---------------- */ shadow_type = makeArrayTypeName(typeName); @@ -702,19 +690,32 @@ DefineType(char *typeName, List *parameters) static char * defGetString(DefElem *def) { - char *string; - - if (nodeTag(def->arg) == T_String) - string = strVal(def->arg); - else if (nodeTag(def->arg) == T_TypeName) - string = ((TypeName *) def->arg)->name; - else - string = NULL; -#if 0 - elog(ERROR, "Define: \"%s\" = what?", def->defname); -#endif + if (def->arg == NULL) + elog(ERROR, "Define: \"%s\" requires a parameter", + def->defname); + switch (nodeTag(def->arg)) + { + case T_Integer: + { + char *str = palloc(32); - return string; + snprintf(str, 32, "%ld", (long) intVal(def->arg)); + return str; + } + case T_Float: + /* T_Float values are kept in string form, so this type cheat + * works (and doesn't risk losing precision) + */ + return strVal(def->arg); + case T_String: + return strVal(def->arg); + case T_TypeName: + return TypeNameToInternalName((TypeName *) def->arg); + default: + elog(ERROR, "Define: cannot interpret argument of \"%s\"", + def->defname); + } + return NULL; /* keep compiler quiet */ } static double @@ -739,15 +740,32 @@ defGetNumeric(DefElem *def) static int defGetTypeLength(DefElem *def) { - if (nodeTag(def->arg) == T_Integer) - return intVal(def->arg); - else if (nodeTag(def->arg) == T_String && - !strcasecmp(strVal(def->arg), "variable")) - return -1; /* variable length */ - else if (nodeTag(def->arg) == T_TypeName && - !strcasecmp(((TypeName *)(def->arg))->name, "variable")) - return -1; - - elog(ERROR, "Define: \"%s\" = what?", def->defname); - return -1; + if (def->arg == NULL) + elog(ERROR, "Define: \"%s\" requires a parameter", + def->defname); + switch (nodeTag(def->arg)) + { + case T_Integer: + return intVal(def->arg); + case T_Float: + elog(ERROR, "Define: \"%s\" requires an integral value", + def->defname); + break; + case T_String: + if (strcasecmp(strVal(def->arg), "variable") == 0) + return -1; /* variable length */ + break; + case T_TypeName: + /* cope if grammar chooses to believe "variable" is a typename */ + if (strcasecmp(TypeNameToInternalName((TypeName *) def->arg), + "variable") == 0) + return -1; /* variable length */ + break; + default: + elog(ERROR, "Define: cannot interpret argument of \"%s\"", + def->defname); + } + elog(ERROR, "Define: invalid argument for \"%s\"", + def->defname); + return 0; /* keep compiler quiet */ } |