aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y19
-rw-r--r--src/backend/parser/parse_func.c53
-rw-r--r--src/backend/parser/parse_relation.c156
3 files changed, 113 insertions, 115 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 62497957263..6bbf4a4de18 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.485 2005/03/29 17:58:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.486 2005/03/31 22:46:11 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -2544,7 +2544,7 @@ def_elem: ColLabel '=' def_arg
;
/* Note: any simple identifier will be returned as a type name! */
-def_arg: func_return { $$ = (Node *)$1; }
+def_arg: func_type { $$ = (Node *)$1; }
| qual_all_Op { $$ = (Node *)$1; }
| NumericOnly { $$ = (Node *)$1; }
| Sconst { $$ = (Node *)makeString($1); }
@@ -3282,6 +3282,18 @@ CreateFunctionStmt:
n->withClause = $9;
$$ = (Node *)n;
}
+ | CREATE opt_or_replace FUNCTION func_name func_args
+ createfunc_opt_list opt_definition
+ {
+ CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
+ n->replace = $2;
+ n->funcname = $4;
+ n->parameters = $5;
+ n->returnType = NULL;
+ n->options = $6;
+ n->withClause = $7;
+ $$ = (Node *)n;
+ }
;
opt_or_replace:
@@ -3367,7 +3379,7 @@ param_name: function_name
func_return:
func_type
{
- /* We can catch over-specified arguments here if we want to,
+ /* We can catch over-specified results here if we want to,
* but for now better to silently swallow typmod, etc.
* - thomas 2000-03-22
*/
@@ -3424,7 +3436,6 @@ common_func_opt_item:
{
$$ = makeDefElem("volatility", (Node *)makeString("volatile"));
}
-
| EXTERNAL SECURITY DEFINER
{
$$ = makeDefElem("security", (Node *)makeInteger(TRUE));
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 07d52ef5441..64a325f10b7 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.176 2005/03/29 03:01:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.177 2005/03/31 22:46:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,6 +18,7 @@
#include "catalog/catname.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_proc.h"
+#include "funcapi.h"
#include "lib/stringinfo.h"
#include "nodes/makefuncs.h"
#include "parser/parse_agg.h"
@@ -1154,10 +1155,8 @@ make_fn_arguments(ParseState *pstate,
static Node *
ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
{
- Oid argtype;
- Oid argrelid;
- AttrNumber attnum;
- FieldSelect *fselect;
+ TupleDesc tupdesc;
+ int i;
/*
* Special case for whole-row Vars so that we can resolve (foo.*).bar
@@ -1180,27 +1179,31 @@ ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
/*
* Else do it the hard way. Note that if the arg is of RECORD type,
- * we will never recognize a column name, and always assume the item
- * must be a function.
+ * and isn't resolvable as a function with OUT params, we will never
+ * be able to recognize a column name here.
*/
- argtype = exprType(first_arg);
- argrelid = typeidTypeRelid(argtype);
- if (!argrelid)
- return NULL; /* can only happen if RECORD */
-
- attnum = get_attnum(argrelid, funcname);
- if (attnum == InvalidAttrNumber)
- return NULL; /* funcname does not match any column */
-
- /* Success, so generate a FieldSelect expression */
- fselect = makeNode(FieldSelect);
- fselect->arg = (Expr *) first_arg;
- fselect->fieldnum = attnum;
- get_atttypetypmod(argrelid, attnum,
- &fselect->resulttype,
- &fselect->resulttypmod);
-
- return (Node *) fselect;
+ if (get_expr_result_type(first_arg, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+ return NULL; /* unresolvable RECORD type */
+
+ for (i = 0; i < tupdesc->natts; i++)
+ {
+ Form_pg_attribute att = tupdesc->attrs[i];
+
+ if (strcmp(funcname, NameStr(att->attname)) == 0 &&
+ !att->attisdropped)
+ {
+ /* Success, so generate a FieldSelect expression */
+ FieldSelect *fselect = makeNode(FieldSelect);
+
+ fselect->arg = (Expr *) first_arg;
+ fselect->fieldnum = i + 1;
+ fselect->resulttype = att->atttypid;
+ fselect->resulttypmod = att->atttypmod;
+ return (Node *) fselect;
+ }
+ }
+
+ return NULL; /* funcname does not match any column */
}
/*
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 6360e402f86..6e391f4eb8b 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.102 2004/12/31 22:00:27 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.103 2005/03/31 22:46:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,21 +17,20 @@
#include <ctype.h>
#include "access/heapam.h"
-#include "access/htup.h"
#include "catalog/heap.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
+#include "funcapi.h"
#include "nodes/makefuncs.h"
#include "parser/parsetree.h"
-#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
-#include "rewrite/rewriteManip.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+
/* GUC parameter */
bool add_missing_from;
@@ -46,6 +45,10 @@ static void expandRelation(Oid relid, Alias *eref,
int rtindex, int sublevels_up,
bool include_dropped,
List **colnames, List **colvars);
+static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
+ int rtindex, int sublevels_up,
+ bool include_dropped,
+ List **colnames, List **colvars);
static int specialAttNum(const char *attname);
static void warnAutoRange(ParseState *pstate, RangeVar *relation);
@@ -965,8 +968,9 @@ addRangeTableEntryForFunction(ParseState *pstate,
bool inFromCl)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
- Oid funcrettype = exprType(funcexpr);
TypeFuncClass functypclass;
+ Oid funcrettype;
+ TupleDesc tupdesc;
Alias *alias = rangefunc->alias;
List *coldeflist = rangefunc->coldeflist;
Alias *eref;
@@ -982,58 +986,37 @@ addRangeTableEntryForFunction(ParseState *pstate,
rte->eref = eref;
/*
- * Now determine if the function returns a simple or composite type,
- * and check/add column aliases.
+ * Now determine if the function returns a simple or composite type.
+ */
+ functypclass = get_expr_result_type(funcexpr,
+ &funcrettype,
+ &tupdesc);
+
+ /*
+ * A coldeflist is required if the function returns RECORD and hasn't
+ * got a predetermined record type, and is prohibited otherwise.
*/
if (coldeflist != NIL)
{
- /*
- * we *only* allow a coldeflist for functions returning a RECORD
- * pseudo-type
- */
- if (funcrettype != RECORDOID)
+ if (functypclass != TYPEFUNC_RECORD)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("a column definition list is only allowed for functions returning \"record\"")));
}
else
{
- /*
- * ... and a coldeflist is *required* for functions returning a
- * RECORD pseudo-type
- */
- if (funcrettype == RECORDOID)
+ if (functypclass == TYPEFUNC_RECORD)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("a column definition list is required for functions returning \"record\"")));
}
- functypclass = get_type_func_class(funcrettype);
-
if (functypclass == TYPEFUNC_COMPOSITE)
{
/* Composite data type, e.g. a table's row type */
- Oid funcrelid = typeidTypeRelid(funcrettype);
- Relation rel;
-
- if (!OidIsValid(funcrelid)) /* shouldn't happen */
- elog(ERROR, "invalid typrelid for complex type %u", funcrettype);
-
- /*
- * Get the rel's relcache entry. This access ensures that we have
- * an up-to-date relcache entry for the rel.
- */
- rel = relation_open(funcrelid, AccessShareLock);
-
+ Assert(tupdesc);
/* Build the column alias list */
- buildRelationAliases(rel->rd_att, alias, eref);
-
- /*
- * Drop the rel refcount, but keep the access lock till end of
- * transaction so that the table can't be deleted or have its
- * schema modified underneath us.
- */
- relation_close(rel, NoLock);
+ buildRelationAliases(tupdesc, alias, eref);
}
else if (functypclass == TYPEFUNC_SCALAR)
{
@@ -1308,24 +1291,19 @@ expandRTE(List *rtable, int rtindex, int sublevels_up,
case RTE_FUNCTION:
{
/* Function RTE */
- Oid funcrettype = exprType(rte->funcexpr);
- TypeFuncClass functypclass = get_type_func_class(funcrettype);
+ TypeFuncClass functypclass;
+ Oid funcrettype;
+ TupleDesc tupdesc;
+ functypclass = get_expr_result_type(rte->funcexpr,
+ &funcrettype,
+ &tupdesc);
if (functypclass == TYPEFUNC_COMPOSITE)
{
- /*
- * Composite data type, i.e. a table's row type
- *
- * Same as ordinary relation RTE
- */
- Oid funcrelid = typeidTypeRelid(funcrettype);
-
- if (!OidIsValid(funcrelid)) /* shouldn't happen */
- elog(ERROR, "invalid typrelid for complex type %u",
- funcrettype);
-
- expandRelation(funcrelid, rte->eref, rtindex, sublevels_up,
- include_dropped, colnames, colvars);
+ /* Composite data type, e.g. a table's row type */
+ Assert(tupdesc);
+ expandTupleDesc(tupdesc, rte->eref, rtindex, sublevels_up,
+ include_dropped, colnames, colvars);
}
else if (functypclass == TYPEFUNC_SCALAR)
{
@@ -1467,17 +1445,30 @@ expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
List **colnames, List **colvars)
{
Relation rel;
- int varattno;
- int maxattrs;
- int numaliases;
+ /* Get the tupledesc and turn it over to expandTupleDesc */
rel = relation_open(relid, AccessShareLock);
- maxattrs = RelationGetNumberOfAttributes(rel);
- numaliases = list_length(eref->colnames);
+ expandTupleDesc(rel->rd_att, eref, rtindex, sublevels_up, include_dropped,
+ colnames, colvars);
+ relation_close(rel, AccessShareLock);
+}
+
+/*
+ * expandTupleDesc -- expandRTE subroutine
+ */
+static void
+expandTupleDesc(TupleDesc tupdesc, Alias *eref,
+ int rtindex, int sublevels_up,
+ bool include_dropped,
+ List **colnames, List **colvars)
+{
+ int maxattrs = tupdesc->natts;
+ int numaliases = list_length(eref->colnames);
+ int varattno;
for (varattno = 0; varattno < maxattrs; varattno++)
{
- Form_pg_attribute attr = rel->rd_att->attrs[varattno];
+ Form_pg_attribute attr = tupdesc->attrs[varattno];
if (attr->attisdropped)
{
@@ -1519,8 +1510,6 @@ expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
*colvars = lappend(*colvars, varnode);
}
}
-
- relation_close(rel, AccessShareLock);
}
/*
@@ -1662,33 +1651,29 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
case RTE_FUNCTION:
{
/* Function RTE */
- Oid funcrettype = exprType(rte->funcexpr);
- TypeFuncClass functypclass = get_type_func_class(funcrettype);
- List *coldeflist = rte->coldeflist;
+ TypeFuncClass functypclass;
+ Oid funcrettype;
+ TupleDesc tupdesc;
+
+ functypclass = get_expr_result_type(rte->funcexpr,
+ &funcrettype,
+ &tupdesc);
if (functypclass == TYPEFUNC_COMPOSITE)
{
- /*
- * Composite data type, i.e. a table's row type
- *
- * Same as ordinary relation RTE
- */
- Oid funcrelid = typeidTypeRelid(funcrettype);
- HeapTuple tp;
+ /* Composite data type, e.g. a table's row type */
Form_pg_attribute att_tup;
- if (!OidIsValid(funcrelid)) /* shouldn't happen */
- elog(ERROR, "invalid typrelid for complex type %u",
- funcrettype);
+ Assert(tupdesc);
+ /* this is probably a can't-happen case */
+ if (attnum < 1 || attnum > tupdesc->natts)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column %d of relation \"%s\" does not exist",
+ attnum,
+ rte->eref->aliasname)));
- tp = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(funcrelid),
- Int16GetDatum(attnum),
- 0, 0);
- if (!HeapTupleIsValid(tp)) /* shouldn't happen */
- elog(ERROR, "cache lookup failed for attribute %d of relation %u",
- attnum, funcrelid);
- att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ att_tup = tupdesc->attrs[attnum - 1];
/*
* If dropped column, pretend it ain't there. See
@@ -1699,10 +1684,9 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
NameStr(att_tup->attname),
- get_rel_name(funcrelid))));
+ rte->eref->aliasname)));
*vartype = att_tup->atttypid;
*vartypmod = att_tup->atttypmod;
- ReleaseSysCache(tp);
}
else if (functypclass == TYPEFUNC_SCALAR)
{
@@ -1712,7 +1696,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
}
else if (functypclass == TYPEFUNC_RECORD)
{
- ColumnDef *colDef = list_nth(coldeflist, attnum - 1);
+ ColumnDef *colDef = list_nth(rte->coldeflist, attnum - 1);
*vartype = typenameTypeId(colDef->typename);
*vartypmod = -1;