diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-04-09 20:35:55 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-04-09 20:35:55 +0000 |
commit | f2d70d32ebd6c38d4fe93c1a684f5f29e5e76938 (patch) | |
tree | 5d041018177cdf6e9ca3ef0cc2eafac580a5bb0b /src/backend/parser | |
parent | c419c224142eb4bbf6e9a47d2d3626f212fda0fc (diff) | |
download | postgresql-f2d70d32ebd6c38d4fe93c1a684f5f29e5e76938.tar.gz postgresql-f2d70d32ebd6c38d4fe93c1a684f5f29e5e76938.zip |
Functions live in namespaces. Qualified function names work, eg
SELECT schema1.func2(...). Aggregate names can be qualified at the
syntactic level, but the qualification is ignored for the moment.
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; |