diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-10-07 00:58:23 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-10-07 00:58:23 +0000 |
commit | fbd26d69846fcbfb69deee45bdddcc692dd59b07 (patch) | |
tree | 2aee8f89268d64645b1c4c96958a0e575a12e259 /src/backend/commands/define.c | |
parent | 4837270be9cbba925a7003de5980918c3de8fb37 (diff) | |
download | postgresql-fbd26d69846fcbfb69deee45bdddcc692dd59b07.tar.gz postgresql-fbd26d69846fcbfb69deee45bdddcc692dd59b07.zip |
Arrange that no database accesses are attempted during parser() --- this
took some rejiggering of typename and ACL parsing, as well as moving
parse_analyze call out of parser(). Restructure postgres.c processing
so that parse analysis and rewrite are skipped when in abort-transaction
state. Only COMMIT and ABORT statements will be processed beyond the raw
parser() phase. This addresses problem of parser failing with database access
errors while in aborted state (see pghackers discussions around 7/28/00).
Also fix some bugs with COMMIT/ABORT statements appearing in the middle of
a single query input string.
Function, operator, and aggregate arguments/results can now use full
TypeName production, in particular foo[] for array types.
DROP OPERATOR and COMMENT ON OPERATOR were broken for unary operators.
Allow CREATE AGGREGATE to accept unquoted numeric constants for initcond.
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 */ } |