diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/analyze.c | 40 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 140 | ||||
-rw-r--r-- | src/backend/parser/parse_agg.c | 15 | ||||
-rw-r--r-- | src/backend/parser/parse_coerce.c | 27 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 17 | ||||
-rw-r--r-- | src/backend/parser/parse_func.c | 146 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 47 |
7 files changed, 238 insertions, 194 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 0de9c5bb851..8b3f218b83a 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.227 2002/04/05 11:56:51 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.228 2002/04/09 20:35:51 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,6 +22,7 @@ #include "catalog/pg_type.h" #include "nodes/makefuncs.h" #include "parser/analyze.h" +#include "parser/gramparse.h" #include "parser/parsetree.h" #include "parser/parse_agg.h" #include "parser/parse_clause.h" @@ -859,7 +860,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, snamenode->val.type = T_String; snamenode->val.val.str = qstring; funccallnode = makeNode(FuncCall); - funccallnode->funcname = "nextval"; + funccallnode->funcname = SystemFuncName("nextval"); funccallnode->args = makeList1(snamenode); funccallnode->agg_star = false; funccallnode->agg_distinct = false; @@ -1197,7 +1198,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) foreach(columns, index->indexParams) { iparam = (IndexElem *) lfirst(columns); - if (strcmp(key->name, iparam->name) == 0) + if (iparam->name && strcmp(key->name, iparam->name) == 0) elog(ERROR, "%s: column \"%s\" appears twice in %s constraint", cxt->stmtType, key->name, index->primary ? "PRIMARY KEY" : "UNIQUE"); @@ -1206,6 +1207,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) /* OK, add it to the index definition */ iparam = makeNode(IndexElem); iparam->name = pstrdup(key->name); + iparam->funcname = NIL; iparam->args = NIL; iparam->class = NULL; index->indexParams = lappend(index->indexParams, iparam); @@ -1281,7 +1283,9 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) if (index->idxname == NULL && index->indexParams != NIL) { iparam = lfirst(index->indexParams); - index->idxname = CreateIndexName((cxt->relation)->relname, iparam->name, + index->idxname = CreateIndexName(cxt->relation->relname, + iparam->name ? iparam->name : + strVal(llast(iparam->funcname)), "key", cxt->alist); } if (index->idxname == NULL) /* should not happen */ @@ -1292,7 +1296,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) cxt->stmtType, (strcmp(cxt->stmtType, "ALTER TABLE") == 0) ? "ADD " : "", (index->primary ? "PRIMARY KEY" : "UNIQUE"), - index->idxname, (cxt->relation)->relname); + index->idxname, cxt->relation->relname); } } @@ -1365,6 +1369,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt) IndexElem *ielem = lfirst(attr); Ident *pkattr = (Ident *) makeNode(Ident); + Assert(ielem->name); /* no func index here */ pkattr->name = pstrdup(ielem->name); fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr); @@ -1417,7 +1422,8 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt) { IndexElem *indparm = lfirst(indparms); - if (strcmp(indparm->name, pkattr->name) == 0) + if (indparm->name && + strcmp(indparm->name, pkattr->name) == 0) { found = true; break; @@ -1470,7 +1476,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt) fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt); fk_trigger->trigname = fkconstraint->constr_name; fk_trigger->relation = cxt->relation; - fk_trigger->funcname = "RI_FKey_check_ins"; + fk_trigger->funcname = SystemFuncName("RI_FKey_check_ins"); fk_trigger->before = false; fk_trigger->row = true; fk_trigger->actions[0] = 'i'; @@ -1542,21 +1548,21 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt) >> FKCONSTR_ON_DELETE_SHIFT) { case FKCONSTR_ON_KEY_NOACTION: - fk_trigger->funcname = "RI_FKey_noaction_del"; + fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_del"); break; case FKCONSTR_ON_KEY_RESTRICT: fk_trigger->deferrable = false; fk_trigger->initdeferred = false; - fk_trigger->funcname = "RI_FKey_restrict_del"; + fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_del"); break; case FKCONSTR_ON_KEY_CASCADE: - fk_trigger->funcname = "RI_FKey_cascade_del"; + fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_del"); break; case FKCONSTR_ON_KEY_SETNULL: - fk_trigger->funcname = "RI_FKey_setnull_del"; + fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_del"); break; case FKCONSTR_ON_KEY_SETDEFAULT: - fk_trigger->funcname = "RI_FKey_setdefault_del"; + fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_del"); break; default: elog(ERROR, "Only one ON DELETE action can be specified for FOREIGN KEY constraint"); @@ -1614,21 +1620,21 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt) >> FKCONSTR_ON_UPDATE_SHIFT) { case FKCONSTR_ON_KEY_NOACTION: - fk_trigger->funcname = "RI_FKey_noaction_upd"; + fk_trigger->funcname = SystemFuncName("RI_FKey_noaction_upd"); break; case FKCONSTR_ON_KEY_RESTRICT: fk_trigger->deferrable = false; fk_trigger->initdeferred = false; - fk_trigger->funcname = "RI_FKey_restrict_upd"; + fk_trigger->funcname = SystemFuncName("RI_FKey_restrict_upd"); break; case FKCONSTR_ON_KEY_CASCADE: - fk_trigger->funcname = "RI_FKey_cascade_upd"; + fk_trigger->funcname = SystemFuncName("RI_FKey_cascade_upd"); break; case FKCONSTR_ON_KEY_SETNULL: - fk_trigger->funcname = "RI_FKey_setnull_upd"; + fk_trigger->funcname = SystemFuncName("RI_FKey_setnull_upd"); break; case FKCONSTR_ON_KEY_SETDEFAULT: - fk_trigger->funcname = "RI_FKey_setdefault_upd"; + fk_trigger->funcname = SystemFuncName("RI_FKey_setdefault_upd"); break; default: elog(ERROR, "Only one ON UPDATE action can be specified for FOREIGN KEY constraint"); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 6ba8766e1ac..3488fb0762f 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.300 2002/04/05 11:56:53 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.301 2002/04/09 20:35:51 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -175,8 +175,9 @@ static bool set_name_needs_quotes(const char *name); %type <str> relation_name, copy_file_name, copy_delimiter, copy_null, database_name, access_method_clause, access_method, attr_name, - class, index_name, name, function_name, file_name, - func_name, handler_name + class, index_name, name, function_name, file_name + +%type <list> func_name, handler_name %type <range> qualified_name, OptConstrFromTable @@ -1859,9 +1860,9 @@ opt_trusted: TRUSTED { $$ = TRUE; } * Work around by using name and dotted_name separately. */ handler_name: name - { $$ = $1; } + { $$ = makeList1(makeString($1)); } | dotted_name - { $$ = strVal(lfirst($1)); /* XXX changing soon */ } + { $$ = $1; } ; opt_lancompiler: LANCOMPILER Sconst { $$ = $2; } @@ -2081,7 +2082,7 @@ DefineStmt: CREATE AGGREGATE func_name definition { DefineStmt *n = makeNode(DefineStmt); n->defType = AGGREGATE; - n->defnames = makeList1(makeString($3)); /* XXX */ + n->defnames = $3; n->definition = $4; $$ = (Node *)n; } @@ -2199,54 +2200,21 @@ TruncateStmt: TRUNCATE opt_table qualified_name * *****************************************************************************/ -CommentStmt: COMMENT ON comment_type name IS comment_text +CommentStmt: COMMENT ON comment_type any_name IS comment_text { CommentStmt *n = makeNode(CommentStmt); n->objtype = $3; n->objname = $4; - n->objproperty = NULL; - n->objlist = NULL; + n->objargs = NIL; n->comment = $6; $$ = (Node *) n; } - | COMMENT ON COLUMN ColId '.' attr_name IS comment_text - { - /* - * We can't use qualified_name here as the '.' causes a shift/red; - * with ColId we do not test for NEW and OLD as table names, but it is OK - * as they would fail anyway as COMMENT cannot appear in a RULE. - * ColumnRef is also innapropriate as we don't take subscripts - * or '*' and have a very precise number of elements (2 or 3) - * so we do it from scratch. - */ - CommentStmt *n = makeNode(CommentStmt); - n->objtype = COLUMN; - n->objschema = NULL; - n->objname = $4; - n->objproperty = $6; - n->objlist = NULL; - n->comment = $8; - $$ = (Node *) n; - } - | COMMENT ON COLUMN ColId '.' ColId '.' attr_name IS comment_text - { - CommentStmt *n = makeNode(CommentStmt); - n->objtype = COLUMN; - n->objschema = $4; - n->objname = $6; - n->objproperty = $8; - n->objlist = NULL; - n->comment = $10; - $$ = (Node *) n; - } | COMMENT ON AGGREGATE func_name '(' aggr_argtype ')' IS comment_text { CommentStmt *n = makeNode(CommentStmt); n->objtype = AGGREGATE; - n->objschema = NULL; n->objname = $4; - n->objproperty = NULL; - n->objlist = makeList1($6); + n->objargs = makeList1($6); n->comment = $9; $$ = (Node *) n; } @@ -2254,10 +2222,8 @@ CommentStmt: COMMENT ON comment_type name IS comment_text { CommentStmt *n = makeNode(CommentStmt); n->objtype = FUNCTION; - n->objschema = NULL; n->objname = $4; - n->objproperty = NULL; - n->objlist = $5; + n->objargs = $5; n->comment = $7; $$ = (Node *) n; } @@ -2265,28 +2231,24 @@ CommentStmt: COMMENT ON comment_type name IS comment_text { CommentStmt *n = makeNode(CommentStmt); n->objtype = OPERATOR; - n->objschema = NULL; - n->objname = $4; - n->objproperty = NULL; - n->objlist = $6; + n->objname = makeList1(makeString($4)); /* XXX */ + n->objargs = $6; n->comment = $9; $$ = (Node *) n; } - | COMMENT ON TRIGGER name ON qualified_name IS comment_text + | COMMENT ON TRIGGER name ON any_name IS comment_text { CommentStmt *n = makeNode(CommentStmt); n->objtype = TRIGGER; - /* NOTE: schemaname here refers to the table in objproperty */ - n->objschema = $6->schemaname; - n->objname = $4; - n->objproperty = $6->relname; - n->objlist = NULL; + n->objname = lappend($6, makeString($4)); + n->objargs = NIL; n->comment = $8; $$ = (Node *) n; } ; -comment_type: DATABASE { $$ = DATABASE; } +comment_type: COLUMN { $$ = COLUMN; } + | DATABASE { $$ = DATABASE; } | INDEX { $$ = INDEX; } | RULE { $$ = RULE; } | SEQUENCE { $$ = SEQUENCE; } @@ -2650,7 +2612,8 @@ index_list: index_list ',' index_elem { $$ = lappend($1, $3); } func_index: func_name '(' name_list ')' opt_class { $$ = makeNode(IndexElem); - $$->name = $1; + $$->name = NULL; + $$->funcname = $1; $$->args = $3; $$->class = $5; } @@ -2660,6 +2623,7 @@ index_elem: attr_name opt_class { $$ = makeNode(IndexElem); $$->name = $1; + $$->funcname = NIL; $$->args = NIL; $$->class = $2; } @@ -2726,7 +2690,7 @@ ProcedureStmt: CREATE opt_or_replace FUNCTION func_name func_args { ProcedureStmt *n = makeNode(ProcedureStmt); n->replace = $2; - n->funcname = makeList1(makeString($4)); /* XXX */ + n->funcname = $4; n->argTypes = $5; n->returnType = $7; n->withClause = $12; @@ -4680,7 +4644,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens FuncCall *n = makeNode(FuncCall); List *largs = $2; List *rargs = $6; - n->funcname = xlateSqlFunc("overlaps"); + n->funcname = SystemFuncName("overlaps"); if (length(largs) == 1) largs = lappend(largs, $2); else if (length(largs) != 2) @@ -4755,7 +4719,7 @@ a_expr: c_expr | a_expr AT TIME ZONE c_expr { FuncCall *n = makeNode(FuncCall); - n->funcname = "timezone"; + n->funcname = SystemFuncName("timezone"); n->args = makeList2($5, $1); n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -4820,7 +4784,7 @@ a_expr: c_expr | a_expr LIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); - n->funcname = "like_escape"; + n->funcname = SystemFuncName("like_escape"); n->args = makeList2($3, $5); n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -4831,7 +4795,7 @@ a_expr: c_expr | a_expr NOT LIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); - n->funcname = "like_escape"; + n->funcname = SystemFuncName("like_escape"); n->args = makeList2($4, $6); n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -4842,7 +4806,7 @@ a_expr: c_expr | a_expr ILIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); - n->funcname = "like_escape"; + n->funcname = SystemFuncName("like_escape"); n->args = makeList2($3, $5); n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -4853,7 +4817,7 @@ a_expr: c_expr | a_expr NOT ILIKE a_expr ESCAPE a_expr { FuncCall *n = makeNode(FuncCall); - n->funcname = "like_escape"; + n->funcname = SystemFuncName("like_escape"); n->args = makeList2($4, $6); n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5300,7 +5264,7 @@ c_expr: columnref | CURRENT_USER opt_empty_parentheses { FuncCall *n = makeNode(FuncCall); - n->funcname = "current_user"; + n->funcname = SystemFuncName("current_user"); n->args = NIL; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5309,7 +5273,7 @@ c_expr: columnref | SESSION_USER opt_empty_parentheses { FuncCall *n = makeNode(FuncCall); - n->funcname = "session_user"; + n->funcname = SystemFuncName("session_user"); n->args = NIL; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5318,7 +5282,7 @@ c_expr: columnref | USER opt_empty_parentheses { FuncCall *n = makeNode(FuncCall); - n->funcname = "current_user"; + n->funcname = SystemFuncName("current_user"); n->args = NIL; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5327,7 +5291,7 @@ c_expr: columnref | EXTRACT '(' extract_list ')' { FuncCall *n = makeNode(FuncCall); - n->funcname = "date_part"; + n->funcname = SystemFuncName("date_part"); n->args = $3; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5337,7 +5301,7 @@ c_expr: columnref { /* position(A in B) is converted to position(B, A) */ FuncCall *n = makeNode(FuncCall); - n->funcname = "position"; + n->funcname = SystemFuncName("position"); n->args = $3; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5349,7 +5313,7 @@ c_expr: columnref * substring(A, B, C) - thomas 2000-11-28 */ FuncCall *n = makeNode(FuncCall); - n->funcname = "substring"; + n->funcname = SystemFuncName("substring"); n->args = $3; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5361,7 +5325,7 @@ c_expr: columnref * - thomas 1997-07-19 */ FuncCall *n = makeNode(FuncCall); - n->funcname = "btrim"; + n->funcname = SystemFuncName("btrim"); n->args = $4; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5370,7 +5334,7 @@ c_expr: columnref | TRIM '(' LEADING trim_list ')' { FuncCall *n = makeNode(FuncCall); - n->funcname = "ltrim"; + n->funcname = SystemFuncName("ltrim"); n->args = $4; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5379,7 +5343,7 @@ c_expr: columnref | TRIM '(' TRAILING trim_list ')' { FuncCall *n = makeNode(FuncCall); - n->funcname = "rtrim"; + n->funcname = SystemFuncName("rtrim"); n->args = $4; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5388,7 +5352,7 @@ c_expr: columnref | TRIM '(' trim_list ')' { FuncCall *n = makeNode(FuncCall); - n->funcname = "btrim"; + n->funcname = SystemFuncName("btrim"); n->args = $3; n->agg_star = FALSE; n->agg_distinct = FALSE; @@ -5798,19 +5762,11 @@ class: ColId { $$ = $1; }; index_name: ColId { $$ = $1; }; file_name: Sconst { $$ = $1; }; -/* func_name will soon return a List ... but not yet */ -/* func_name: function_name - { $$ = makeList1(makeString($1)); } + { $$ = makeList1(makeString(xlateSqlFunc($1))); } | dotted_name { $$ = $1; } ; -*/ -func_name: function_name - { $$ = $1; } - | dotted_name - { $$ = strVal(lfirst($1)); } - ; /* Constants @@ -5942,9 +5898,9 @@ type_name: IDENT { $$ = $1; } /* Function identifier --- names that can be function names. */ -function_name: IDENT { $$ = xlateSqlFunc($1); } - | unreserved_keyword { $$ = xlateSqlFunc($1); } - | func_name_keyword { $$ = xlateSqlFunc($1); } +function_name: IDENT { $$ = $1; } + | unreserved_keyword { $$ = $1; } + | func_name_keyword { $$ = $1; } ; /* Column label --- allowed labels in "AS" clauses. @@ -6459,6 +6415,8 @@ makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg) /* xlateSqlFunc() * Convert alternate function names to internal Postgres functions. * + * NOTE: these conversions are only applied to unqualified function names. + * * Do not convert "float", since that is handled elsewhere * for FLOAT(p) syntax. * @@ -6482,6 +6440,8 @@ xlateSqlFunc(char *name) /* xlateSqlType() * Convert alternate type names to internal Postgres types. * + * NOTE: these conversions are only applied to unqualified type names. + * * NB: do NOT put "char" -> "bpchar" here, because that renders it impossible * to refer to our single-byte char type, even with quotes. (Without quotes, * CHAR is a keyword, and the code above produces "bpchar" for it.) @@ -6521,6 +6481,14 @@ xlateSqlType(char *name) return name; } /* xlateSqlType() */ +/* SystemFuncName() + * Build a properly-qualified reference to a built-in function. + */ +List * +SystemFuncName(char *name) +{ + return makeList2(makeString("pg_catalog"), makeString(name)); +} void parser_init(Oid *typev, int nargs) { diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index dc939a71801..3812579a4db 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -8,12 +8,13 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.47 2002/03/21 16:00:58 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.48 2002/04/09 20:35:52 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "catalog/namespace.h" #include "catalog/pg_aggregate.h" #include "optimizer/clauses.h" #include "optimizer/tlist.h" @@ -187,7 +188,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual) Aggref * -ParseAgg(ParseState *pstate, char *aggname, Oid basetype, +ParseAgg(ParseState *pstate, List *aggname, Oid basetype, List *args, bool agg_star, bool agg_distinct) { HeapTuple aggtuple; @@ -195,7 +196,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype, Aggref *aggref; aggtuple = SearchSysCache(AGGNAME, - PointerGetDatum(aggname), + PointerGetDatum(strVal(llast(aggname))), ObjectIdGetDatum(basetype), 0, 0); /* shouldn't happen --- caller should have checked already */ @@ -218,7 +219,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype, */ aggref = makeNode(Aggref); - aggref->aggname = pstrdup(aggname); + aggref->aggname = pstrdup(strVal(llast(aggname))); aggref->basetype = aggform->aggbasetype; aggref->aggtype = aggform->aggfinaltype; aggref->target = lfirst(args); @@ -237,7 +238,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype, * basetype */ void -agg_error(char *caller, char *aggname, Oid basetypeID) +agg_error(const char *caller, List *aggname, Oid basetypeID) { /* * basetypeID that is Invalid (zero) means aggregate over all types. @@ -246,8 +247,8 @@ agg_error(char *caller, char *aggname, Oid basetypeID) if (basetypeID == InvalidOid) elog(ERROR, "%s: aggregate '%s' for all types does not exist", - caller, aggname); + caller, NameListToString(aggname)); else elog(ERROR, "%s: aggregate '%s' for type %s does not exist", - caller, aggname, format_type_be(basetypeID)); + caller, NameListToString(aggname), format_type_be(basetypeID)); } diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 690a047915a..4dd5777e1e1 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.68 2002/03/20 19:44:22 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.69 2002/04/09 20:35:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -657,7 +657,8 @@ PreferredType(CATEGORY category, Oid type) * Look for a coercion function between two types. * * A coercion function must be named after (the internal name of) its - * result type, and must accept exactly the specified input type. + * result type, and must accept exactly the specified input type. We + * also require it to be defined in the same namespace as its result type. * * This routine is also used to look for length-coercion functions, which * are similar but accept a second argument. secondArgType is the type @@ -669,14 +670,19 @@ PreferredType(CATEGORY category, Oid type) static Oid find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType) { - char *funcname; + Type targetType; + char *typname; + Oid typnamespace; Oid oid_array[FUNC_MAX_ARGS]; int nargs; HeapTuple ftup; Form_pg_proc pform; Oid funcid; - funcname = typeidTypeName(targetTypeId); + targetType = typeidType(targetTypeId); + typname = NameStr(((Form_pg_type) GETSTRUCT(targetType))->typname); + typnamespace = ((Form_pg_type) GETSTRUCT(targetType))->typnamespace; + MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid)); oid_array[0] = inputTypeId; if (OidIsValid(secondArgType)) @@ -687,22 +693,27 @@ find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType) else nargs = 1; - ftup = SearchSysCache(PROCNAME, - PointerGetDatum(funcname), - Int32GetDatum(nargs), + ftup = SearchSysCache(PROCNAMENSP, + CStringGetDatum(typname), + Int16GetDatum(nargs), PointerGetDatum(oid_array), - 0); + ObjectIdGetDatum(typnamespace)); if (!HeapTupleIsValid(ftup)) + { + ReleaseSysCache(targetType); return InvalidOid; + } /* Make sure the function's result type is as expected, too */ pform = (Form_pg_proc) GETSTRUCT(ftup); if (pform->prorettype != targetTypeId) { ReleaseSysCache(ftup); + ReleaseSysCache(targetType); return InvalidOid; } funcid = ftup->t_data->t_oid; ReleaseSysCache(ftup); + ReleaseSysCache(targetType); return funcid; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 2a5a7698d85..f8449716061 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.112 2002/03/29 19:06:11 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.113 2002/04/09 20:35:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -129,7 +129,8 @@ transformExpr(ParseState *pstate, Node *expr) /* handle qualification, if any */ foreach(fields, pref->fields) { - result = ParseFuncOrColumn(pstate, strVal(lfirst(fields)), + result = ParseFuncOrColumn(pstate, + makeList1(lfirst(fields)), makeList1(result), false, false, true); } @@ -158,7 +159,8 @@ transformExpr(ParseState *pstate, Node *expr) /* handle qualification, if any */ foreach(fields, efs->fields) { - result = ParseFuncOrColumn(pstate, strVal(lfirst(fields)), + result = ParseFuncOrColumn(pstate, + makeList1(lfirst(fields)), makeList1(result), false, false, true); } @@ -728,7 +730,8 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) rv = makeNode(RangeVar); rv->relname = name1; rv->inhOpt = INH_DEFAULT; - node = ParseFuncOrColumn(pstate, name2, + node = ParseFuncOrColumn(pstate, + makeList1(makeString(name2)), makeList1(rv), false, false, true); } @@ -761,7 +764,8 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) rv->schemaname = name1; rv->relname = name2; rv->inhOpt = INH_DEFAULT; - node = ParseFuncOrColumn(pstate, name3, + node = ParseFuncOrColumn(pstate, + makeList1(makeString(name3)), makeList1(rv), false, false, true); } @@ -801,7 +805,8 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) rv->schemaname = name2; rv->relname = name3; rv->inhOpt = INH_DEFAULT; - node = ParseFuncOrColumn(pstate, name4, + node = ParseFuncOrColumn(pstate, + makeList1(makeString(name4)), makeList1(rv), false, false, true); } diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 578402fd255..a86195126ff 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.124 2002/04/06 06:59:22 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.125 2002/04/09 20:35:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -54,7 +54,7 @@ static int match_argtypes(int nargs, static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid); static FuncCandidateList func_select_candidate(int nargs, Oid *input_typeids, FuncCandidateList candidates); -static int agg_get_candidates(char *aggname, Oid typeId, +static int agg_get_candidates(List *aggname, Oid typeId, FuncCandidateList *candidates); static Oid agg_select_candidate(Oid typeid, FuncCandidateList candidates); @@ -64,22 +64,22 @@ static Oid agg_select_candidate(Oid typeid, FuncCandidateList candidates); * * For historical reasons, Postgres tries to treat the notations tab.col * and col(tab) as equivalent: if a single-argument function call has an - * argument of complex type and the function name matches any attribute - * of the type, we take it as a column projection. + * argument of complex type and the (unqualified) function name matches + * any attribute of the type, we take it as a column projection. * * Hence, both cases come through here. The is_column parameter tells us * which syntactic construct is actually being dealt with, but this is * intended to be used only to deliver an appropriate error message, * not to affect the semantics. When is_column is true, we should have - * a single argument (the putative table), function name equal to the - * column name, and no aggregate decoration. + * a single argument (the putative table), unqualified function name + * equal to the column name, and no aggregate decoration. * * In the function-call case, the argument expressions have been transformed * already. In the column case, we may get either a transformed expression * or a RangeVar node as argument. */ Node * -ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, +ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, bool agg_star, bool agg_distinct, bool is_column) { Oid rettype; @@ -113,23 +113,28 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, { first_arg = lfirst(fargs); if (first_arg == NULL) /* should not happen */ - elog(ERROR, "Function '%s' does not allow NULL input", funcname); + elog(ERROR, "Function '%s' does not allow NULL input", + NameListToString(funcname)); } /* * check for column projection: if function has one argument, and that - * argument is of complex type, then the function could be a projection. + * argument is of complex type, and function name is not qualified, + * then the "function call" could be a projection. We also check + * that there wasn't any aggregate decoration. */ - /* We only have one parameter, and it's not got aggregate decoration */ - if (nargs == 1 && !must_be_agg) + if (nargs == 1 && !must_be_agg && length(funcname) == 1) { + char *cname = strVal(lfirst(funcname)); + /* Is it a not-yet-transformed RangeVar node? */ if (IsA(first_arg, RangeVar)) { /* First arg is a relation. This could be a projection. */ refname = ((RangeVar *) first_arg)->relname; - retval = qualifiedNameToVar(pstate, refname, funcname, true); + /* XXX WRONG: ignores possible qualification of argument */ + retval = qualifiedNameToVar(pstate, refname, cname, true); if (retval) return retval; } @@ -140,9 +145,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, * ParseComplexProjection can't handle the projection, we have * to keep going. */ - retval = ParseComplexProjection(pstate, - funcname, - first_arg); + retval = ParseComplexProjection(pstate, cname, first_arg); if (retval) return retval; } @@ -175,7 +178,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, /* try for exact match first... */ if (SearchSysCacheExists(AGGNAME, - PointerGetDatum(funcname), + PointerGetDatum(strVal(llast(funcname))), ObjectIdGetDatum(basetype), 0, 0)) return (Node *) ParseAgg(pstate, funcname, basetype, @@ -183,7 +186,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, /* check for aggregate-that-accepts-any-type (eg, COUNT) */ if (SearchSysCacheExists(AGGNAME, - PointerGetDatum(funcname), + PointerGetDatum(strVal(llast(funcname))), ObjectIdGetDatum(0), 0, 0)) return (Node *) ParseAgg(pstate, funcname, 0, @@ -211,7 +214,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, { /* Multiple possible matches --- give up */ elog(ERROR, "Unable to select an aggregate function %s(%s)", - funcname, format_type_be(basetype)); + NameListToString(funcname), format_type_be(basetype)); } } @@ -222,7 +225,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, * function could not have been meant. */ elog(ERROR, "There is no aggregate function %s(%s)", - funcname, format_type_be(basetype)); + NameListToString(funcname), format_type_be(basetype)); } } @@ -275,7 +278,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, */ if (is_column) elog(ERROR, "No such attribute %s.%s", - refname, funcname); + refname, strVal(lfirst(funcname))); else { elog(ERROR, "Cannot pass result of sub-select or join %s to a function", @@ -329,7 +332,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, * give an error message that is appropriate for that case. */ if (is_column) - elog(ERROR, "Attribute \"%s\" not found", funcname); + elog(ERROR, "Attribute \"%s\" not found", + strVal(lfirst(funcname))); /* Else generate a detailed complaint */ func_error(NULL, funcname, nargs, oid_array, "Unable to identify a function that satisfies the " @@ -373,7 +377,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, static int -agg_get_candidates(char *aggname, +agg_get_candidates(List *aggname, Oid typeId, FuncCandidateList *candidates) { @@ -388,7 +392,7 @@ agg_get_candidates(char *aggname, ScanKeyEntryInitialize(&aggKey[0], 0, Anum_pg_aggregate_aggname, F_NAMEEQ, - NameGetDatum(aggname)); + NameGetDatum(strVal(llast(aggname)))); pg_aggregate_desc = heap_openr(AggregateRelationName, AccessShareLock); pg_aggregate_scan = systable_beginscan(pg_aggregate_desc, @@ -862,7 +866,7 @@ func_select_candidate(int nargs, * d) if the answer is zero, try the next array from vector #1 */ FuncDetailCode -func_get_detail(char *funcname, +func_get_detail(List *funcname, List *fargs, int nargs, Oid *argtypes, @@ -875,7 +879,7 @@ func_get_detail(char *funcname, FuncCandidateList best_candidate; /* Get list of possible candidates from namespace search */ - function_typeids = FuncnameGetCandidates(makeList1(makeString(funcname)), nargs); + function_typeids = FuncnameGetCandidates(funcname, nargs); /* * See if there is an exact match @@ -917,15 +921,11 @@ func_get_detail(char *funcname, if (nargs == 1) { Oid targetType; + TypeName *tn = makeNode(TypeName); - /* XXX WRONG: need to search searchpath for name; but little - * point in fixing before we revise this code for qualified - * funcnames too. - */ - targetType = GetSysCacheOid(TYPENAMENSP, - PointerGetDatum(funcname), - ObjectIdGetDatum(PG_CATALOG_NAMESPACE), - 0, 0); + tn->names = funcname; + tn->typmod = -1; + targetType = LookupTypeName(tn); if (OidIsValid(targetType) && !ISCOMPLEX(targetType)) { @@ -1409,7 +1409,7 @@ ParseComplexProjection(ParseState *pstate, * argument types */ void -func_error(const char *caller, const char *funcname, +func_error(const char *caller, List *funcname, int nargs, const Oid *argtypes, const char *msg) { @@ -1439,13 +1439,87 @@ func_error(const char *caller, const char *funcname, if (caller == NULL) { elog(ERROR, "Function '%s(%s)' does not exist%s%s", - funcname, p, + NameListToString(funcname), p, ((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : "")); } else { elog(ERROR, "%s: function '%s(%s)' does not exist%s%s", - caller, funcname, p, + caller, NameListToString(funcname), p, ((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : "")); } } + +/* + * LookupFuncName + * Given a possibly-qualified function name and a set of argument types, + * look up the function. Returns InvalidOid if no such function. + * + * If the function name is not schema-qualified, it is sought in the current + * namespace search path. + */ +Oid +LookupFuncName(List *funcname, int nargs, const Oid *argtypes) +{ + FuncCandidateList clist; + + clist = FuncnameGetCandidates(funcname, nargs); + + while (clist) + { + if (memcmp(argtypes, clist->args, nargs * sizeof(Oid)) == 0) + return clist->oid; + clist = clist->next; + } + + return InvalidOid; +} + +/* + * LookupFuncNameTypeNames + * Like LookupFuncName, but the argument types are specified by a + * list of TypeName nodes. Also, if we fail to find the function + * and caller is not NULL, then an error is reported via func_error. + * + * "opaque" is accepted as a typename only if opaqueOK is true. + */ +Oid +LookupFuncNameTypeNames(List *funcname, List *argtypes, bool opaqueOK, + const char *caller) +{ + Oid funcoid; + Oid argoids[FUNC_MAX_ARGS]; + int argcount; + int i; + + MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid)); + argcount = length(argtypes); + if (argcount > FUNC_MAX_ARGS) + elog(ERROR, "functions cannot have more than %d arguments", + FUNC_MAX_ARGS); + + for (i = 0; i < argcount; i++) + { + TypeName *t = (TypeName *) lfirst(argtypes); + + argoids[i] = LookupTypeName(t); + if (!OidIsValid(argoids[i])) + { + char *typnam = TypeNameToString(t); + + if (opaqueOK && strcmp(typnam, "opaque") == 0) + argoids[i] = InvalidOid; + else + elog(ERROR, "Type \"%s\" does not exist", typnam); + } + + argtypes = lnext(argtypes); + } + + funcoid = LookupFuncName(funcname, argcount, argoids); + + if (!OidIsValid(funcoid) && caller != NULL) + func_error(caller, funcname, argcount, argoids, NULL); + + return funcoid; +} diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index e8e82a45c3b..83c53de5d1d 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.82 2002/04/05 11:56:53 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.83 2002/04/09 20:35:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -498,48 +498,34 @@ FigureColnameInternal(Node *node, char **name) return 2; case T_ColumnRef: { - List *fields = ((ColumnRef *) node)->fields; + char *cname = strVal(llast(((ColumnRef *) node)->fields)); - while (lnext(fields) != NIL) - fields = lnext(fields); - if (strcmp(strVal(lfirst(fields)), "*") != 0) + if (strcmp(cname, "*") != 0) { - *name = strVal(lfirst(fields)); + *name = cname; return 2; } } break; case T_ExprFieldSelect: { - List *fields = ((ExprFieldSelect *) node)->fields; + char *fname = strVal(llast(((ExprFieldSelect *) node)->fields)); - if (fields) + if (strcmp(fname, "*") != 0) { - while (lnext(fields) != NIL) - fields = lnext(fields); - if (strcmp(strVal(lfirst(fields)), "*") != 0) - { - *name = strVal(lfirst(fields)); - return 2; - } + *name = fname; + return 2; } } break; case T_FuncCall: - *name = ((FuncCall *) node)->funcname; + *name = strVal(llast(((FuncCall *) node)->funcname)); return 2; case T_A_Const: if (((A_Const *) node)->typename != NULL) { - List *names = ((A_Const *) node)->typename->names; - - if (names != NIL) - { - while (lnext(names) != NIL) - names = lnext(names); - *name = strVal(lfirst(names)); - return 1; - } + *name = strVal(llast(((A_Const *) node)->typename->names)); + return 1; } break; case T_TypeCast: @@ -549,15 +535,8 @@ FigureColnameInternal(Node *node, char **name) { if (((TypeCast *) node)->typename != NULL) { - List *names = ((TypeCast *) node)->typename->names; - - if (names != NIL) - { - while (lnext(names) != NIL) - names = lnext(names); - *name = strVal(lfirst(names)); - return 1; - } + *name = strVal(llast(((TypeCast *) node)->typename->names)); + return 1; } } break; |