diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 7afd6659e1af28620ea691a6f78a5d000b237f22..b5d039f9355ef63831e56edcf35786f811afee7c 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.43 2002/04/01 14:22:41 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.44 2002/04/09 20:35:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -272,6 +272,7 @@ boot_index_param:
 				{
 					IndexElem *n = makeNode(IndexElem);
 					n->name = LexIDStr($1);
+					n->funcname = n->args = NIL; /* no func indexes */
 					n->class = LexIDStr($2);
 					$$ = n;
 				}
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 00c52e89c4b80da4f5ff2836733ff1c75997d278..07f49c75ab2cffa3b4ac1c21a017730abb0c0d72 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.61 2002/03/31 06:26:29 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.62 2002/04/09 20:35:46 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -283,51 +283,6 @@ ExecuteGrantStmt_Table(GrantStmt *stmt)
 }
 
 
-static Oid
-find_function_with_arglist(char *name, List *arguments)
-{
-	Oid		oid;
-	Oid		argoids[FUNC_MAX_ARGS];
-	int		i;
-	int16	argcount;
-
-	MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid));
-	argcount = length(arguments);
-	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(arguments);
-
-		argoids[i] = LookupTypeName(t);
-		if (!OidIsValid(argoids[i]))
-		{
-			char      *typnam = TypeNameToString(t);
-
-			if (strcmp(typnam, "opaque") == 0)
-				argoids[i] = InvalidOid;
-			else
-				elog(ERROR, "Type \"%s\" does not exist", typnam);
-		}
-
-		arguments = lnext(arguments);
-	}
-
-	oid = GetSysCacheOid(PROCNAME,
-						 PointerGetDatum(name),
-						 Int16GetDatum(argcount),
-						 PointerGetDatum(argoids),
-						 0);
-
-	if (!OidIsValid(oid))
-		func_error(NULL, name, argcount, argoids, NULL);
-
-	return oid;
-}
-
-
 static void
 ExecuteGrantStmt_Function(GrantStmt *stmt)
 {
@@ -365,7 +320,8 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
 		char		nulls[Natts_pg_proc];
 		char		replaces[Natts_pg_proc];
 
-		oid = find_function_with_arglist(func->funcname, func->funcargs);
+		oid = LookupFuncNameTypeNames(func->funcname, func->funcargs,
+									  true, "GRANT");
 		relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
 		tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(oid), 0, 0, 0);
 		if (!HeapTupleIsValid(tuple))
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index a7d73bbf272240050e271d9d37508f2a44ab1541..6880dbe19e396e1b92424b79c1c8c54fddb88c42 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.6 2002/04/06 06:59:21 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.7 2002/04/09 20:35:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,7 @@
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_shadow.h"
+#include "lib/stringinfo.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "storage/backendid.h"
@@ -367,7 +368,7 @@ FuncnameGetCandidates(List *names, int nargs)
 	}
 
 	/* Search syscache by name and nargs only */
-	catlist = SearchSysCacheList(PROCNAME, 2,
+	catlist = SearchSysCacheList(PROCNAMENSP, 2,
 								 CStringGetDatum(funcname),
 								 Int16GetDatum(nargs),
 								 0, 0);
@@ -564,6 +565,29 @@ makeRangeVarFromNameList(List *names)
 	return rel;
 }
 
+/*
+ * NameListToString
+ *		Utility routine to convert a qualified-name list into a string.
+ *		Used primarily to form error messages.
+ */
+char *
+NameListToString(List *names)
+{
+	StringInfoData string;
+	List		*l;
+
+	initStringInfo(&string);
+
+	foreach(l, names)
+	{
+		if (l != names)
+			appendStringInfoChar(&string, '.');
+		appendStringInfo(&string, "%s", strVal(lfirst(l)));
+	}
+
+	return string.data;
+}
+
 /*
  * isTempNamespace - is the given namespace my temporary-table namespace?
  */
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 1a73f42c3344a78792b6f28483dc3e64a9772043..a9f270fccf8afd718e3b17da992d2f3d5f9882c7 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.42 2002/03/29 19:06:01 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.43 2002/04/09 20:35:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 #include "access/heapam.h"
 #include "catalog/catname.h"
 #include "catalog/indexing.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
@@ -33,8 +34,8 @@
 void
 AggregateCreate(const char *aggName,
 				Oid aggNamespace,
-				char *aggtransfnName,
-				char *aggfinalfnName,
+				List *aggtransfnName,
+				List *aggfinalfnName,
 				Oid aggBaseType,
 				Oid aggTransType,
 				const char *agginitval)
@@ -79,19 +80,18 @@ AggregateCreate(const char *aggName,
 	}
 	else
 		nargs = 1;
-	tup = SearchSysCache(PROCNAME,
-						 PointerGetDatum(aggtransfnName),
-						 Int32GetDatum(nargs),
-						 PointerGetDatum(fnArgs),
-						 0);
+	transfn = LookupFuncName(aggtransfnName, nargs, fnArgs);
+	if (!OidIsValid(transfn))
+		func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
+	tup = SearchSysCache(PROCOID,
+						 ObjectIdGetDatum(transfn),
+						 0, 0, 0);
 	if (!HeapTupleIsValid(tup))
 		func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
-	transfn = tup->t_data->t_oid;
-	Assert(OidIsValid(transfn));
 	proc = (Form_pg_proc) GETSTRUCT(tup);
 	if (proc->prorettype != aggTransType)
 		elog(ERROR, "return type of transition function %s is not %s",
-			 aggtransfnName, typeidTypeName(aggTransType));
+			 NameListToString(aggtransfnName), typeidTypeName(aggTransType));
 
 	/*
 	 * If the transfn is strict and the initval is NULL, make sure input
@@ -111,15 +111,14 @@ AggregateCreate(const char *aggName,
 	{
 		fnArgs[0] = aggTransType;
 		fnArgs[1] = 0;
-		tup = SearchSysCache(PROCNAME,
-							 PointerGetDatum(aggfinalfnName),
-							 Int32GetDatum(1),
-							 PointerGetDatum(fnArgs),
-							 0);
+		finalfn = LookupFuncName(aggfinalfnName, 1, fnArgs);
+		if (!OidIsValid(finalfn))
+			func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
+		tup = SearchSysCache(PROCOID,
+							 ObjectIdGetDatum(finalfn),
+							 0, 0, 0);
 		if (!HeapTupleIsValid(tup))
 			func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
-		finalfn = tup->t_data->t_oid;
-		Assert(OidIsValid(finalfn));
 		proc = (Form_pg_proc) GETSTRUCT(tup);
 		finaltype = proc->prorettype;
 		ReleaseSysCache(tup);
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 8942c266fd6b9d68c41c37a50be3a6c3e74acee7..41023b7edc8c8266a09ebaf377e3bbad8a39aa7b 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.64 2002/03/29 19:06:01 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.65 2002/04/09 20:35:47 tgl Exp $
  *
  * NOTES
  *	  these routines moved here from commands/define.c and somewhat cleaned up.
@@ -27,6 +27,7 @@
 #include "parser/parse_func.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
@@ -42,13 +43,13 @@ static Oid OperatorShellMake(const char *operatorName,
 static void OperatorDef(const char *operatorName,
 			Oid leftTypeId,
 			Oid rightTypeId,
-			const char *procedureName,
+			List *procedureName,
 			uint16 precedence,
 			bool isLeftAssociative,
 			const char *commutatorName,
 			const char *negatorName,
-			const char *restrictionName,
-			const char *joinName,
+			List *restrictionName,
+			List *joinName,
 			bool canHash,
 			const char *leftSortName,
 			const char *rightSortName);
@@ -373,13 +374,13 @@ static void
 OperatorDef(const char *operatorName,
 			Oid leftTypeId,
 			Oid rightTypeId,
-			const char *procedureName,
+			List *procedureName,
 			uint16 precedence,
 			bool isLeftAssociative,
 			const char *commutatorName,
 			const char *negatorName,
-			const char *restrictionName,
-			const char *joinName,
+			List *restrictionName,
+			List *joinName,
 			bool canHash,
 			const char *leftSortName,
 			const char *rightSortName)
@@ -398,6 +399,7 @@ OperatorDef(const char *operatorName,
 	const char *name[4];
 	Oid			typeId[FUNC_MAX_ARGS];
 	int			nargs;
+	Oid			procOid;
 	NameData	oname;
 	TupleDesc	tupDesc;
 	ScanKeyData opKey[3];
@@ -456,19 +458,12 @@ OperatorDef(const char *operatorName,
 		typeId[1] = rightTypeId;
 		nargs = 2;
 	}
-	tup = SearchSysCache(PROCNAME,
-						 PointerGetDatum(procedureName),
-						 Int32GetDatum(nargs),
-						 PointerGetDatum(typeId),
-						 0);
-	if (!HeapTupleIsValid(tup))
+	procOid = LookupFuncName(procedureName, nargs, typeId);
+	if (!OidIsValid(procOid))
 		func_error("OperatorDef", procedureName, nargs, typeId, NULL);
 
-	values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
-	values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
-											GETSTRUCT(tup))->prorettype);
-
-	ReleaseSysCache(tup);
+	values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procOid);
+	values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(get_func_rettype(procOid));
 
 	/*
 	 * find restriction estimator
@@ -483,11 +478,7 @@ OperatorDef(const char *operatorName,
 		typeId[2] = 0;			/* args list (opaque type) */
 		typeId[3] = INT4OID;	/* varRelid */
 
-		restOid = GetSysCacheOid(PROCNAME,
-								 PointerGetDatum(restrictionName),
-								 Int32GetDatum(4),
-								 PointerGetDatum(typeId),
-								 0);
+		restOid = LookupFuncName(restrictionName, 4, typeId);
 		if (!OidIsValid(restOid))
 			func_error("OperatorDef", restrictionName, 4, typeId, NULL);
 
@@ -508,11 +499,7 @@ OperatorDef(const char *operatorName,
 		typeId[1] = OIDOID;		/* operator OID */
 		typeId[2] = 0;			/* args list (opaque type) */
 
-		joinOid = GetSysCacheOid(PROCNAME,
-								 PointerGetDatum(joinName),
-								 Int32GetDatum(3),
-								 PointerGetDatum(typeId),
-								 0);
+		joinOid = LookupFuncName(joinName, 3, typeId);
 		if (!OidIsValid(joinOid))
 			func_error("OperatorDef", joinName, 3, typeId, NULL);
 
@@ -950,13 +937,13 @@ OperatorCreate(const char *operatorName,
 	OperatorDef(operatorName,
 				leftTypeId,
 				rightTypeId,
-				procedureName,
+				makeList1(makeString((char*) procedureName)), /* XXX */
 				precedence,
 				isLeftAssociative,
 				commutatorName,
 				negatorName,
-				restrictionName,
-				joinName,
+				restrictionName ? makeList1(makeString((char*) restrictionName)) : NIL,	/* XXX */
+				joinName ? makeList1(makeString((char*) joinName)) : NIL, /* XXX */
 				canHash,
 				leftSortName,
 				rightSortName);
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 02f76e7679a942f34b12bd59abfa3a9533c93ac3..8cb89b979cbab9f2a0d5f92a23e85743e1e19b94 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.68 2002/04/05 00:31:25 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.69 2002/04/09 20:35:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -271,11 +271,11 @@ ProcedureCreate(const char *procedureName,
 	tupDesc = rel->rd_att;
 
 	/* Check for pre-existing definition */
-	oldtup = SearchSysCache(PROCNAME,
+	oldtup = SearchSysCache(PROCNAMENSP,
 							PointerGetDatum(procedureName),
 							UInt16GetDatum(parameterCount),
 							PointerGetDatum(typev),
-							0);
+							ObjectIdGetDatum(procNamespace));
 
 	if (HeapTupleIsValid(oldtup))
 	{
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index f8e5bc6fc6fd6fe3fe96c274ea191c6d0f5d9fe8..b7d57f6cce5959c3c1577a99d9d656cda4766d72 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -7,7 +7,7 @@
  * Copyright (c) 1999-2001, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.38 2002/03/29 19:06:04 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.39 2002/04/09 20:35:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "access/heapam.h"
 #include "catalog/catname.h"
 #include "catalog/indexing.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_description.h"
 #include "catalog/pg_namespace.h"
@@ -40,87 +41,74 @@
 #include "utils/syscache.h"
 
 
-/*------------------------------------------------------------------
+/*
  * Static Function Prototypes --
  *
  * The following protoypes are declared static so as not to conflict
  * with any other routines outside this module. These routines are
  * called by the public function CommentObject() routine to create
  * the appropriate comment for the specific object type.
- *------------------------------------------------------------------
  */
 
-static void CommentRelation(int objtype, char * schemaname, char *relation,
-							char *comment);
-static void CommentAttribute(char * schemaname, char *relation,
-							 char *attrib, char *comment);
-static void CommentDatabase(char *database, char *comment);
-static void CommentRewrite(char *rule, char *comment);
-static void CommentType(char *type, char *comment);
-static void CommentAggregate(char *aggregate, List *arguments, char *comment);
-static void CommentProc(char *function, List *arguments, char *comment);
-static void CommentOperator(char *opname, List *arguments, char *comment);
-static void CommentTrigger(char *trigger, char *schemaname, char *relation,
-						   char *comments);
-
-
-/*------------------------------------------------------------------
+static void CommentRelation(int objtype, List *relname, char *comment);
+static void CommentAttribute(List *qualname, char *comment);
+static void CommentDatabase(List *qualname, char *comment);
+static void CommentRule(List *qualname, char *comment);
+static void CommentType(List *typename, char *comment);
+static void CommentAggregate(List *aggregate, List *arguments, char *comment);
+static void CommentProc(List *function, List *arguments, char *comment);
+static void CommentOperator(List *qualname, List *arguments, char *comment);
+static void CommentTrigger(List *qualname, char *comment);
+
+
+/*
  * CommentObject --
  *
  * This routine is used to add the associated comment into
- * pg_description for the object specified by the paramters handed
- * to this routine. If the routine cannot determine an Oid to
- * associated with the parameters handed to this routine, an
- * error is thrown. Otherwise the comment is added to pg_description
- * by calling the CreateComments() routine. If the comment string is
- * empty, CreateComments() will drop any comments associated with
- * the object.
- *------------------------------------------------------------------
-*/
-
+ * pg_description for the object specified by the given SQL command.
+ */
 void
-CommentObject(int objtype, char *schemaname, char *objname, char *objproperty,
-			  List *objlist, char *comment)
+CommentObject(CommentStmt *stmt)
 {
-	switch (objtype)
+	switch (stmt->objtype)
 	{
 		case INDEX:
 		case SEQUENCE:
 		case TABLE:
 		case VIEW:
-			CommentRelation(objtype, schemaname, objname, comment);
+			CommentRelation(stmt->objtype, stmt->objname, stmt->comment);
 			break;
 		case COLUMN:
-			CommentAttribute(schemaname, objname, objproperty, comment);
+			CommentAttribute(stmt->objname, stmt->comment);
 			break;
 		case DATABASE:
-			CommentDatabase(objname, comment);
+			CommentDatabase(stmt->objname, stmt->comment);
 			break;
 		case RULE:
-			CommentRewrite(objname, comment);
+			CommentRule(stmt->objname, stmt->comment);
 			break;
 		case TYPE_P:
-			CommentType(objname, comment);
+			CommentType(stmt->objname, stmt->comment);
 			break;
 		case AGGREGATE:
-			CommentAggregate(objname, objlist, comment);
+			CommentAggregate(stmt->objname, stmt->objargs, stmt->comment);
 			break;
 		case FUNCTION:
-			CommentProc(objname, objlist, comment);
+			CommentProc(stmt->objname, stmt->objargs, stmt->comment);
 			break;
 		case OPERATOR:
-			CommentOperator(objname, objlist, comment);
+			CommentOperator(stmt->objname, stmt->objargs, stmt->comment);
 			break;
 		case TRIGGER:
-			CommentTrigger(objname, schemaname, objproperty, comment);
+			CommentTrigger(stmt->objname, stmt->comment);
 			break;
 		default:
 			elog(ERROR, "An attempt was made to comment on a unknown type: %d",
-				 objtype);
+				 stmt->objtype);
 	}
 }
 
-/*------------------------------------------------------------------
+/*
  * CreateComments --
  *
  * Create a comment for the specified object descriptor.  Inserts a new
@@ -128,9 +116,7 @@ CommentObject(int objtype, char *schemaname, char *objname, char *objproperty,
  *
  * If the comment given is null or an empty string, instead delete any
  * existing comment for the specified key.
- *------------------------------------------------------------------
  */
-
 void
 CreateComments(Oid oid, Oid classoid, int32 subid, char *comment)
 {
@@ -254,15 +240,13 @@ CreateComments(Oid oid, Oid classoid, int32 subid, char *comment)
 	heap_close(description, NoLock);
 }
 
-/*------------------------------------------------------------------
+/*
  * DeleteComments --
  *
  * This routine is used to purge all comments associated with an object,
  * regardless of their objsubid.  It is called, for example, when a relation
  * is destroyed.
- *------------------------------------------------------------------
  */
-
 void
 DeleteComments(Oid oid, Oid classoid)
 {
@@ -316,7 +300,7 @@ DeleteComments(Oid oid, Oid classoid)
 	heap_close(description, NoLock);
 }
 
-/*------------------------------------------------------------------
+/*
  * CommentRelation --
  *
  * This routine is used to add/drop a comment from a relation, where
@@ -324,20 +308,14 @@ DeleteComments(Oid oid, Oid classoid)
  * finds the relation name by searching the system cache, locating
  * the appropriate tuple, and inserting a comment using that
  * tuple's oid. Its parameters are the relation name and comments.
- *------------------------------------------------------------------
  */
-
 static void
-CommentRelation(int reltype, char *schemaname, char *relname, char *comment)
+CommentRelation(int objtype, List *relname, char *comment)
 {
 	Relation	relation;
-	RangeVar   *tgtrel = makeNode(RangeVar);
-	
-	
-	tgtrel->relname = relname;
-	tgtrel->schemaname = schemaname;
-	/* FIXME SCHEMA: Can we add comments to temp relations? */
-	tgtrel->istemp = false;
+	RangeVar   *tgtrel;
+
+	tgtrel = makeRangeVarFromNameList(relname);
 
 	/*
 	 * Open the relation.  We do this mainly to acquire a lock that
@@ -349,27 +327,32 @@ CommentRelation(int reltype, char *schemaname, char *relname, char *comment)
 
 	/* Check object security */
 	if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
-		elog(ERROR, "you are not permitted to comment on class '%s'", relname);
+		elog(ERROR, "you are not permitted to comment on class '%s'",
+			 RelationGetRelationName(relation));
 
 	/* Next, verify that the relation type matches the intent */
 
-	switch (reltype)
+	switch (objtype)
 	{
 		case INDEX:
 			if (relation->rd_rel->relkind != RELKIND_INDEX)
-				elog(ERROR, "relation '%s' is not an index", relname);
+				elog(ERROR, "relation '%s' is not an index",
+					 RelationGetRelationName(relation));
 			break;
 		case TABLE:
 			if (relation->rd_rel->relkind != RELKIND_RELATION)
-				elog(ERROR, "relation '%s' is not a table", relname);
+				elog(ERROR, "relation '%s' is not a table",
+					 RelationGetRelationName(relation));
 			break;
 		case VIEW:
 			if (relation->rd_rel->relkind != RELKIND_VIEW)
-				elog(ERROR, "relation '%s' is not a view", relname);
+				elog(ERROR, "relation '%s' is not a view",
+					 RelationGetRelationName(relation));
 			break;
 		case SEQUENCE:
 			if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
-				elog(ERROR, "relation '%s' is not a sequence", relname);
+				elog(ERROR, "relation '%s' is not a sequence",
+					 RelationGetRelationName(relation));
 			break;
 	}
 
@@ -381,7 +364,7 @@ CommentRelation(int reltype, char *schemaname, char *relname, char *comment)
 	relation_close(relation, NoLock);
 }
 
-/*------------------------------------------------------------------
+/*
  * CommentAttribute --
  *
  * This routine is used to add/drop a comment from an attribute
@@ -390,34 +373,40 @@ CommentRelation(int reltype, char *schemaname, char *relname, char *comment)
  * attribute. If successful, a comment is added/dropped, else an
  * elog() exception is thrown.	The parameters are the relation
  * and attribute names, and the comments
- *------------------------------------------------------------------
-*/
-
+ */
 static void
-CommentAttribute(char *schemaname, char *relname, char *attrname, char *comment)
+CommentAttribute(List *qualname, char *comment)
 {
-	RangeVar   *rel = makeNode(RangeVar);
+	int			nnames;
+	List	   *relname;
+	char	   *attrname;
+	RangeVar   *rel;
 	Relation	relation;
 	AttrNumber	attnum;
 
-	/* Open the containing relation to ensure it won't go away meanwhile */
+	/* Separate relname and attr name */
+	nnames = length(qualname);
+	if (nnames < 2)
+		elog(ERROR, "CommentAttribute: must specify relation.attribute");
+	relname = ltruncate(nnames-1, listCopy(qualname));
+	attrname = strVal(nth(nnames-1, qualname));
 
-	rel->relname = relname;
-	rel->schemaname = schemaname;
-	rel->istemp = false;
+	/* Open the containing relation to ensure it won't go away meanwhile */
+	rel = makeRangeVarFromNameList(relname);
 	relation = heap_openrv(rel, AccessShareLock);
 
 	/* Check object security */
 
 	if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
-		elog(ERROR, "you are not permitted to comment on class '%s'", relname);
+		elog(ERROR, "you are not permitted to comment on class '%s'",
+			 RelationGetRelationName(relation));
 
 	/* Now, fetch the attribute number from the system cache */
 
 	attnum = get_attnum(RelationGetRelid(relation), attrname);
 	if (attnum == InvalidAttrNumber)
 		elog(ERROR, "'%s' is not an attribute of class '%s'",
-			 attrname, relname);
+			 attrname, RelationGetRelationName(relation));
 
 	/* Create the comment using the relation's oid */
 
@@ -429,7 +418,7 @@ CommentAttribute(char *schemaname, char *relname, char *attrname, char *comment)
 	heap_close(relation, NoLock);
 }
 
-/*------------------------------------------------------------------
+/*
  * CommentDatabase --
  *
  * This routine is used to add/drop any user-comments a user might
@@ -437,23 +426,26 @@ CommentAttribute(char *schemaname, char *relname, char *attrname, char *comment)
  * security for owner permissions, and, if succesful, will then
  * attempt to find the oid of the database specified. Once found,
  * a comment is added/dropped using the CreateComments() routine.
- *------------------------------------------------------------------
-*/
-
+ */
 static void
-CommentDatabase(char *database, char *comment)
+CommentDatabase(List *qualname, char *comment)
 {
+	char	   *database;
 	Relation	pg_database;
 	ScanKeyData entry;
 	HeapScanDesc scan;
 	HeapTuple	dbtuple;
 	Oid			oid;
 
+	if (length(qualname) != 1)
+		elog(ERROR, "CommentDatabase: database name may not be qualified");
+	database = strVal(lfirst(qualname));
+
 	/* First find the tuple in pg_database for the database */
 
 	pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
 	ScanKeyEntryInitialize(&entry, 0, Anum_pg_database_datname,
-						   F_NAMEEQ, NameGetDatum(database));
+						   F_NAMEEQ, CStringGetDatum(database));
 	scan = heap_beginscan(pg_database, 0, SnapshotNow, 1, &entry);
 	dbtuple = heap_getnext(scan, 0);
 
@@ -479,25 +471,29 @@ CommentDatabase(char *database, char *comment)
 	heap_close(pg_database, AccessShareLock);
 }
 
-/*------------------------------------------------------------------
- * CommentRewrite --
+/*
+ * CommentRule --
  *
  * This routine is used to add/drop any user-comments a user might
  * have regarding a specified RULE. The rule is specified by name
  * and, if found, and the user has appropriate permissions, a
  * comment will be added/dropped using the CreateComments() routine.
- *------------------------------------------------------------------
-*/
-
+ */
 static void
-CommentRewrite(char *rule, char *comment)
+CommentRule(List *qualname, char *comment)
 {
+	char	   *rule;
 	HeapTuple	tuple;
 	Oid			reloid;
 	Oid			ruleoid;
 	Oid			classoid;
 	int32		aclcheck;
 
+	/* XXX this is gonna change soon */
+	if (length(qualname) != 1)
+		elog(ERROR, "CommentRule: rule name may not be qualified");
+	rule = strVal(lfirst(qualname));
+
 	/* Find the rule's pg_rewrite tuple, get its OID and its table's OID */
 
 	tuple = SearchSysCache(RULENAME,
@@ -528,7 +524,7 @@ CommentRewrite(char *rule, char *comment)
 	CreateComments(ruleoid, classoid, 0, comment);
 }
 
-/*------------------------------------------------------------------
+/*
  * CommentType --
  *
  * This routine is used to add/drop any user-comments a user might
@@ -536,42 +532,43 @@ CommentRewrite(char *rule, char *comment)
  * and, if found, and the user has appropriate permissions, a
  * comment will be added/dropped using the CreateComments() routine.
  * The type's name and the comments are the paramters to this routine.
- *------------------------------------------------------------------
-*/
-
+ */
 static void
-CommentType(char *type, char *comment)
+CommentType(List *typename, char *comment)
 {
+	TypeName   *tname;
 	Oid			oid;
 
+	/* XXX a bit of a crock; should accept TypeName in COMMENT syntax */
+	tname = makeNode(TypeName);
+	tname->names = typename;
+	tname->typmod = -1;
+
 	/* Find the type's oid */
 
-	/* XXX WRONG: need to deal with qualified type names */
-	oid = typenameTypeId(makeTypeName(type));
+	oid = typenameTypeId(tname);
 
 	/* Check object security */
 
 	if (!pg_type_ownercheck(oid, GetUserId()))
-		elog(ERROR, "you are not permitted to comment on type '%s'",
-			 type);
+		elog(ERROR, "you are not permitted to comment on type %s",
+			 TypeNameToString(tname));
 
 	/* Call CreateComments() to create/drop the comments */
 
 	CreateComments(oid, RelOid_pg_type, 0, comment);
 }
 
-/*------------------------------------------------------------------
+/*
  * CommentAggregate --
  *
  * This routine is used to allow a user to provide comments on an
  * aggregate function. The aggregate function is determined by both
  * its name and its argument type, which, with the comments are
  * the three parameters handed to this routine.
- *------------------------------------------------------------------
-*/
-
+ */
 static void
-CommentAggregate(char *aggregate, List *arguments, char *comment)
+CommentAggregate(List *aggregate, List *arguments, char *comment)
 {
 	TypeName   *aggtype = (TypeName *) lfirst(arguments);
 	Oid			baseoid,
@@ -587,7 +584,7 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
 	/* Now, attempt to find the actual tuple in pg_aggregate */
 
 	oid = GetSysCacheOid(AGGNAME,
-						 PointerGetDatum(aggregate),
+						 PointerGetDatum(strVal(lfirst(aggregate))), /* XXX */
 						 ObjectIdGetDatum(baseoid),
 						 0, 0);
 	if (!OidIsValid(oid))
@@ -598,11 +595,11 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
 	if (!pg_aggr_ownercheck(oid, GetUserId()))
 	{
 		if (baseoid == InvalidOid)
-			elog(ERROR, "you are not permitted to comment on aggregate '%s' for all types",
-				 aggregate);
+			elog(ERROR, "you are not permitted to comment on aggregate %s for all types",
+				 NameListToString(aggregate));
 		else
-			elog(ERROR, "you are not permitted to comment on aggregate '%s' for type %s",
-				 aggregate, format_type_be(baseoid));
+			elog(ERROR, "you are not permitted to comment on aggregate %s for type %s",
+				 NameListToString(aggregate), format_type_be(baseoid));
 	}
 
 	/* pg_aggregate doesn't have a hard-coded OID, so must look it up */
@@ -615,7 +612,7 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
 	CreateComments(oid, classoid, 0, comment);
 }
 
-/*------------------------------------------------------------------
+/*
  * CommentProc --
  *
  * This routine is used to allow a user to provide comments on an
@@ -623,64 +620,29 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
  * its name and its argument list. The argument list is expected to
  * be a series of parsed nodes pointed to by a List object. If the
  * comments string is empty, the associated comment is dropped.
- *------------------------------------------------------------------
-*/
-
+ */
 static void
-CommentProc(char *function, List *arguments, char *comment)
+CommentProc(List *function, List *arguments, char *comment)
 {
-	Oid			oid,
-				argoids[FUNC_MAX_ARGS];
-	int			i,
-				argcount;
-
-	/* First, initialize function's argument list with their type oids */
-
-	MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid));
-	argcount = length(arguments);
-	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(arguments);
-
-		argoids[i] = LookupTypeName(t);
-		if (!OidIsValid(argoids[i]))
-		{
-			char      *typnam = TypeNameToString(t);
-
-			if (strcmp(typnam, "opaque") == 0)
-				argoids[i] = InvalidOid;
-			else
-				elog(ERROR, "Type \"%s\" does not exist", typnam);
-		}
+	Oid			oid;
 
-		arguments = lnext(arguments);
-	}
+	/* Look up the procedure */
 
-	/* Now, find the corresponding oid for this procedure */
-
-	oid = GetSysCacheOid(PROCNAME,
-						 PointerGetDatum(function),
-						 Int32GetDatum(argcount),
-						 PointerGetDatum(argoids),
-						 0);
-	if (!OidIsValid(oid))
-		func_error("CommentProc", function, argcount, argoids, NULL);
+	oid = LookupFuncNameTypeNames(function, arguments,
+								  true, "CommentProc");
 
 	/* Now, validate the user's ability to comment on this function */
 
 	if (!pg_proc_ownercheck(oid, GetUserId()))
-		elog(ERROR, "you are not permitted to comment on function '%s'",
-			 function);
+		elog(ERROR, "you are not permitted to comment on function %s",
+			 NameListToString(function));
 
 	/* Call CreateComments() to create/drop the comments */
 
 	CreateComments(oid, RelOid_pg_proc, 0, comment);
 }
 
-/*------------------------------------------------------------------
+/*
  * CommentOperator --
  *
  * This routine is used to allow a user to provide comments on an
@@ -694,12 +656,11 @@ CommentProc(char *function, List *arguments, char *comment)
  * NOTE: we actually attach the comment to the procedure that underlies
  * the operator.  This is a feature, not a bug: we want the same comment
  * to be visible for both operator and function.
- *------------------------------------------------------------------
-*/
-
+ */
 static void
-CommentOperator(char *opername, List *arguments, char *comment)
+CommentOperator(List *qualname, List *arguments, char *comment)
 {
+	char	   *opername = strVal(lfirst(qualname)); /* XXX */
 	TypeName   *typenode1 = (TypeName *) lfirst(arguments);
 	TypeName   *typenode2 = (TypeName *) lsecond(arguments);
 	char		oprtype = 0;
@@ -760,21 +721,22 @@ CommentOperator(char *opername, List *arguments, char *comment)
 	CreateComments(oid, RelOid_pg_proc, 0, comment);
 }
 
-/*------------------------------------------------------------------
+/*
  * CommentTrigger --
  *
  * This routine is used to allow a user to provide comments on a
  * trigger event. The trigger for commenting is determined by both
  * its name and the relation to which it refers. The arguments to this
- * function are the trigger name, the relation name, and the comments
- * to add/drop.
- *------------------------------------------------------------------
-*/
-
+ * function are the trigger name and relation name (merged into a qualified
+ * name), and the comment to add/drop.
+ */
 static void
-CommentTrigger(char *trigger, char *schemaname, char *relname, char *comment)
+CommentTrigger(List *qualname, char *comment)
 {
-	RangeVar   *rel = makeNode(RangeVar);
+	int			nnames;
+	List	   *relname;
+	char	   *trigname;
+	RangeVar   *rel;
 	Relation	pg_trigger,
 				relation;
 	HeapTuple	triggertuple;
@@ -782,16 +744,22 @@ CommentTrigger(char *trigger, char *schemaname, char *relname, char *comment)
 	ScanKeyData entry[2];
 	Oid			oid;
 
-	/* First, validate the user's action */
+	/* Separate relname and trig name */
+	nnames = length(qualname);
+	if (nnames < 2)
+		elog(ERROR, "CommentTrigger: must specify relation and trigger");
+	relname = ltruncate(nnames-1, listCopy(qualname));
+	trigname = strVal(nth(nnames-1, qualname));
 
-	rel->relname = relname;
-	rel->schemaname = schemaname;
-	rel->istemp = false;
+	/* Open the owning relation to ensure it won't go away meanwhile */
+	rel = makeRangeVarFromNameList(relname);
 	relation = heap_openrv(rel, AccessShareLock);
 
+	/* Check object security */
+
 	if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
-		elog(ERROR, "you are not permitted to comment on trigger '%s' %s '%s'",
-			 trigger, "defined for relation", relname);
+		elog(ERROR, "you are not permitted to comment on trigger '%s' for relation '%s'",
+			 trigname, RelationGetRelationName(relation));
 
 	/* Fetch the trigger oid from pg_trigger  */
 
@@ -801,15 +769,15 @@ CommentTrigger(char *trigger, char *schemaname, char *relname, char *comment)
 						   ObjectIdGetDatum(RelationGetRelid(relation)));
 	ScanKeyEntryInitialize(&entry[1], 0x0, Anum_pg_trigger_tgname,
 						   F_NAMEEQ,
-						   NameGetDatum(trigger));
+						   CStringGetDatum(trigname));
 	scan = heap_beginscan(pg_trigger, 0, SnapshotNow, 2, entry);
 	triggertuple = heap_getnext(scan, 0);
 
 	/* If no trigger exists for the relation specified, notify user */
 
 	if (!HeapTupleIsValid(triggertuple))
-		elog(ERROR, "trigger '%s' defined for relation '%s' does not exist",
-			 trigger, relname);
+		elog(ERROR, "trigger '%s' for relation '%s' does not exist",
+			 trigname, RelationGetRelationName(relation));
 
 	oid = triggertuple->t_data->t_oid;
 
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index eaff4e66dfa80d262f50206828d62da93348cfcf..cccbcdfaa5922ec6bfed384e90cba9a86a634103 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.73 2002/04/05 00:31:25 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.74 2002/04/09 20:35:47 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -60,9 +60,10 @@
 #include "utils/syscache.h"
 
 
-static Oid	findTypeIOFunction(const char *procname, bool isOutput);
+static Oid	findTypeIOFunction(List *procname, bool isOutput);
 static char *defGetString(DefElem *def);
 static double defGetNumeric(DefElem *def);
+static List *defGetQualifiedName(DefElem *def);
 static TypeName *defGetTypeName(DefElem *def);
 static int	defGetTypeLength(DefElem *def);
 
@@ -474,8 +475,8 @@ DefineAggregate(List *names, List *parameters)
 {
 	char	   *aggName;
 	Oid			aggNamespace;
-	char	   *transfuncName = NULL;
-	char	   *finalfuncName = NULL;
+	List	   *transfuncName = NIL;
+	List	   *finalfuncName = NIL;
 	TypeName   *baseType = NULL;
 	TypeName   *transType = NULL;
 	char	   *initval = NULL;
@@ -495,11 +496,11 @@ DefineAggregate(List *names, List *parameters)
 		 * spellings for sfunc, stype, initcond.
 		 */
 		if (strcasecmp(defel->defname, "sfunc") == 0)
-			transfuncName = defGetString(defel);
+			transfuncName = defGetQualifiedName(defel);
 		else if (strcasecmp(defel->defname, "sfunc1") == 0)
-			transfuncName = defGetString(defel);
+			transfuncName = defGetQualifiedName(defel);
 		else if (strcasecmp(defel->defname, "finalfunc") == 0)
-			finalfuncName = defGetString(defel);
+			finalfuncName = defGetQualifiedName(defel);
 		else if (strcasecmp(defel->defname, "basetype") == 0)
 			baseType = defGetTypeName(defel);
 		else if (strcasecmp(defel->defname, "stype") == 0)
@@ -522,7 +523,7 @@ DefineAggregate(List *names, List *parameters)
 		elog(ERROR, "Define: \"basetype\" unspecified");
 	if (transType == NULL)
 		elog(ERROR, "Define: \"stype\" unspecified");
-	if (transfuncName == NULL)
+	if (transfuncName == NIL)
 		elog(ERROR, "Define: \"sfunc\" unspecified");
 
 	/*
@@ -800,10 +801,10 @@ DefineType(List *names, List *parameters)
 	int16		internalLength = -1;	/* int2 */
 	int16		externalLength = -1;	/* int2 */
 	Oid			elemType = InvalidOid;
-	char	   *inputName = NULL;
-	char	   *outputName = NULL;
-	char	   *sendName = NULL;
-	char	   *receiveName = NULL;
+	List	   *inputName = NIL;
+	List	   *outputName = NIL;
+	List	   *sendName = NIL;
+	List	   *receiveName = NIL;
 	char	   *defaultValue = NULL;
 	bool		byValue = false;
 	char		delimiter = DEFAULT_TYPDELIM;
@@ -838,13 +839,13 @@ DefineType(List *names, List *parameters)
 		else if (strcasecmp(defel->defname, "externallength") == 0)
 			externalLength = defGetTypeLength(defel);
 		else if (strcasecmp(defel->defname, "input") == 0)
-			inputName = defGetString(defel);
+			inputName = defGetQualifiedName(defel);
 		else if (strcasecmp(defel->defname, "output") == 0)
-			outputName = defGetString(defel);
+			outputName = defGetQualifiedName(defel);
 		else if (strcasecmp(defel->defname, "send") == 0)
-			sendName = defGetString(defel);
+			sendName = defGetQualifiedName(defel);
 		else if (strcasecmp(defel->defname, "receive") == 0)
-			receiveName = defGetString(defel);
+			receiveName = defGetQualifiedName(defel);
 		else if (strcasecmp(defel->defname, "delimiter") == 0)
 		{
 			char	   *p = defGetString(defel);
@@ -909,9 +910,9 @@ DefineType(List *names, List *parameters)
 	/*
 	 * make sure we have our required definitions
 	 */
-	if (inputName == NULL)
+	if (inputName == NIL)
 		elog(ERROR, "Define: \"input\" unspecified");
-	if (outputName == NULL)
+	if (outputName == NIL)
 		elog(ERROR, "Define: \"output\" unspecified");
 
 	/* Convert I/O proc names to OIDs */
@@ -989,7 +990,7 @@ DefineType(List *names, List *parameters)
 }
 
 static Oid
-findTypeIOFunction(const char *procname, bool isOutput)
+findTypeIOFunction(List *procname, bool isOutput)
 {
 	Oid			argList[FUNC_MAX_ARGS];
 	int			nargs;
@@ -1001,11 +1002,7 @@ findTypeIOFunction(const char *procname, bool isOutput)
 	 */
 	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
-	procOid = GetSysCacheOid(PROCNAME,
-							 PointerGetDatum(procname),
-							 Int32GetDatum(1),
-							 PointerGetDatum(argList),
-							 0);
+	procOid = LookupFuncName(procname, 1, argList);
 
 	if (!OidIsValid(procOid))
 	{
@@ -1028,11 +1025,7 @@ findTypeIOFunction(const char *procname, bool isOutput)
 			argList[1] = OIDOID;
 			argList[2] = INT4OID;
 		}
-		procOid = GetSysCacheOid(PROCNAME,
-								 PointerGetDatum(procname),
-								 Int32GetDatum(nargs),
-								 PointerGetDatum(argList),
-								 0);
+		procOid = LookupFuncName(procname, nargs, argList);
 
 		if (!OidIsValid(procOid))
 			func_error("TypeCreate", procname, 1, argList, NULL);
@@ -1094,6 +1087,26 @@ defGetNumeric(DefElem *def)
 	return 0;					/* keep compiler quiet */
 }
 
+static List *
+defGetQualifiedName(DefElem *def)
+{
+	if (def->arg == NULL)
+		elog(ERROR, "Define: \"%s\" requires a parameter",
+			 def->defname);
+	switch (nodeTag(def->arg))
+	{
+		case T_TypeName:
+			return ((TypeName *) def->arg)->names;
+		case T_String:
+			/* Allow quoted name for backwards compatibility */
+			return makeList1(def->arg);
+		default:
+			elog(ERROR, "Define: argument of \"%s\" must be a name",
+				 def->defname);
+	}
+	return NIL;					/* keep compiler quiet */
+}
+
 static TypeName *
 defGetTypeName(DefElem *def)
 {
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b5067f99278fa21659a2fb66759c54f369529483..43539cd625af170521eb1c6a8a4f1c4933a1d8fa 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.67 2002/04/05 00:31:26 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.68 2002/04/09 20:35:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@
 #include "utils/syscache.h"
 
 
-#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL)
+#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->funcname != NIL)
 
 /* non-export function prototypes */
 static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
@@ -297,7 +297,7 @@ FuncIndexArgs(IndexInfo *indexInfo,
 	 * that.  So, check to make sure that the selected function has
 	 * exact-match or binary-compatible input types.
 	 */
-	fdresult = func_get_detail(funcIndex->name, funcIndex->args,
+	fdresult = func_get_detail(funcIndex->funcname, funcIndex->args,
 							   nargs, argTypes,
 							   &funcid, &rettype, &retset,
 							   &true_typeids);
@@ -307,7 +307,8 @@ FuncIndexArgs(IndexInfo *indexInfo,
 			elog(ERROR, "DefineIndex: functional index must use a real function, not a type coercion"
 				 "\n\tTry specifying the index opclass you want to use, instead");
 		else
-			func_error("DefineIndex", funcIndex->name, nargs, argTypes, NULL);
+			func_error("DefineIndex", funcIndex->funcname, nargs, argTypes,
+					   NULL);
 	}
 
 	if (retset)
@@ -316,7 +317,7 @@ FuncIndexArgs(IndexInfo *indexInfo,
 	for (i = 0; i < nargs; i++)
 	{
 		if (!IsBinaryCompatible(argTypes[i], true_typeids[i]))
-			func_error("DefineIndex", funcIndex->name, nargs, argTypes,
+			func_error("DefineIndex", funcIndex->funcname, nargs, argTypes,
 					   "Index function must be binary-compatible with table datatype");
 	}
 
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index d9cf0f0814a380d9c4892a7d85a64865fb787f3e..4ef8d8f72a0bee3b3a69cab019cd467181aa6bd2 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.29 2002/02/18 23:11:11 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.30 2002/04/09 20:35:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,12 +18,15 @@
 #include "access/heapam.h"
 #include "catalog/catname.h"
 #include "catalog/indexing.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_proc.h"
 #include "commands/proclang.h"
 #include "fmgr.h"
 #include "miscadmin.h"
+#include "parser/parse_func.h"
 #include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
@@ -50,15 +53,13 @@ void
 CreateProceduralLanguage(CreatePLangStmt *stmt)
 {
 	char		languageName[NAMEDATALEN];
-	HeapTuple	procTup;
-
+	Oid			procOid;
 	Oid			typev[FUNC_MAX_ARGS];
 	char		nulls[Natts_pg_language];
 	Datum		values[Natts_pg_language];
 	Relation	rel;
 	HeapTuple	tup;
 	TupleDesc	tupDesc;
-
 	int			i;
 
 	/*
@@ -83,18 +84,14 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	 * Lookup the PL handler function and check that it is of return type
 	 * Opaque
 	 */
-	memset(typev, 0, sizeof(typev));
-	procTup = SearchSysCache(PROCNAME,
-							 PointerGetDatum(stmt->plhandler),
-							 Int32GetDatum(0),
-							 PointerGetDatum(typev),
-							 0);
-	if (!HeapTupleIsValid(procTup))
+	MemSet(typev, 0, sizeof(typev));
+	procOid = LookupFuncName(stmt->plhandler, 0, typev);
+	if (!OidIsValid(procOid))
 		elog(ERROR, "PL handler function %s() doesn't exist",
-			 stmt->plhandler);
-	if (((Form_pg_proc) GETSTRUCT(procTup))->prorettype != InvalidOid)
+			 NameListToString(stmt->plhandler));
+	if (get_func_rettype(procOid) != InvalidOid)
 		elog(ERROR, "PL handler function %s() isn't of return type Opaque",
-			 stmt->plhandler);
+			 NameListToString(stmt->plhandler));
 
 	/*
 	 * Insert the new language into pg_language
@@ -109,13 +106,11 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	values[i++] = PointerGetDatum(languageName);
 	values[i++] = BoolGetDatum(true);	/* lanispl */
 	values[i++] = BoolGetDatum(stmt->pltrusted);
-	values[i++] = ObjectIdGetDatum(procTup->t_data->t_oid);
+	values[i++] = ObjectIdGetDatum(procOid);
 	values[i++] = DirectFunctionCall1(textin,
 									  CStringGetDatum(stmt->plcompiler));
 	nulls[i] = 'n';				/* lanacl */
 
-	ReleaseSysCache(procTup);
-
 	rel = heap_openr(LanguageRelationName, RowExclusiveLock);
 
 	tupDesc = rel->rd_att;
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
index fb73fe3bd0236c8ef2b4e2d6f0f37e64ccb66592..8969b9cdc13b9d6e896997bd722d1fc9d4b2dfc3 100644
--- a/src/backend/commands/remove.c
+++ b/src/backend/commands/remove.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.72 2002/03/29 19:06:06 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.73 2002/04/09 20:35:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
@@ -357,60 +358,38 @@ RemoveDomain(List *names, int behavior)
  *		...
  */
 void
-RemoveFunction(char *functionName,		/* function name to be removed */
+RemoveFunction(List *functionName,		/* function name to be removed */
 			   List *argTypes)	/* list of TypeName nodes */
 {
-	int			nargs = length(argTypes);
+	Oid			funcOid;
 	Relation	relation;
 	HeapTuple	tup;
-	Oid			argList[FUNC_MAX_ARGS];
-	int			i;
-
-	if (nargs > FUNC_MAX_ARGS)
-		elog(ERROR, "functions cannot have more than %d arguments",
-			 FUNC_MAX_ARGS);
-	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
-	for (i = 0; i < nargs; i++)
-	{
-		TypeName   *t = (TypeName *) lfirst(argTypes);
-
-		argList[i] = LookupTypeName(t);
-		if (!OidIsValid(argList[i]))
-		{
-			char      *typnam = TypeNameToString(t);
-
-			if (strcmp(typnam, "opaque") == 0)
-				argList[i] = InvalidOid;
-			else
-				elog(ERROR, "Type \"%s\" does not exist", typnam);
-		}
 
-		argTypes = lnext(argTypes);
-	}
+	funcOid = LookupFuncNameTypeNames(functionName, argTypes, 
+									  true, "RemoveFunction");
 
 	relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
 
-	tup = SearchSysCache(PROCNAME,
-						 PointerGetDatum(functionName),
-						 Int32GetDatum(nargs),
-						 PointerGetDatum(argList),
-						 0);
-
-	if (!HeapTupleIsValid(tup))
-		func_error("RemoveFunction", functionName, nargs, argList, NULL);
+	tup = SearchSysCache(PROCOID,
+						 ObjectIdGetDatum(funcOid),
+						 0, 0, 0);
+	if (!HeapTupleIsValid(tup))	/* should not happen */
+		elog(ERROR, "RemoveFunction: couldn't find tuple for function %s",
+			 NameListToString(functionName));
 
-	if (!pg_proc_ownercheck(tup->t_data->t_oid, GetUserId()))
+	if (!pg_proc_ownercheck(funcOid, GetUserId()))
 		elog(ERROR, "RemoveFunction: function '%s': permission denied",
-			 functionName);
+			 NameListToString(functionName));
 
 	if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
 	{
 		/* "Helpful" WARNING when removing a builtin function ... */
-		elog(WARNING, "Removing built-in function \"%s\"", functionName);
+		elog(WARNING, "Removing built-in function \"%s\"",
+			 NameListToString(functionName));
 	}
 
 	/* Delete any comments associated with this function */
-	DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
+	DeleteComments(funcOid, RelationGetRelid(relation));
 
 	simple_heap_delete(relation, &tup->t_self);
 
@@ -420,7 +399,7 @@ RemoveFunction(char *functionName,		/* function name to be removed */
 }
 
 void
-RemoveAggregate(char *aggName, TypeName *aggType)
+RemoveAggregate(List *aggName, TypeName *aggType)
 {
 	Relation	relation;
 	HeapTuple	tup;
@@ -443,7 +422,7 @@ RemoveAggregate(char *aggName, TypeName *aggType)
 	relation = heap_openr(AggregateRelationName, RowExclusiveLock);
 
 	tup = SearchSysCache(AGGNAME,
-						 PointerGetDatum(aggName),
+						 PointerGetDatum(strVal(llast(aggName))),
 						 ObjectIdGetDatum(basetypeID),
 						 0, 0);
 
@@ -453,11 +432,11 @@ RemoveAggregate(char *aggName, TypeName *aggType)
 	if (!pg_aggr_ownercheck(tup->t_data->t_oid, GetUserId()))
 	{
 		if (basetypeID == InvalidOid)
-			elog(ERROR, "RemoveAggregate: aggregate '%s' for all types: permission denied",
-				 aggName);
+			elog(ERROR, "RemoveAggregate: aggregate %s for all types: permission denied",
+				 NameListToString(aggName));
 		else
-			elog(ERROR, "RemoveAggregate: aggregate '%s' for type %s: permission denied",
-				 aggName, format_type_be(basetypeID));
+			elog(ERROR, "RemoveAggregate: aggregate %s for type %s: permission denied",
+				 NameListToString(aggName), format_type_be(basetypeID));
 	}
 
 	/* Remove any comments related to this aggregate */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index c05b2ec51a31b895cdeb882a56bb8ddd69ffd40f..72f13d3db491dd041cface0469dd567463a654ee 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.111 2002/04/01 22:36:10 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.112 2002/04/09 20:35:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,6 +26,7 @@
 #include "commands/trigger.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
+#include "parser/parse_func.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
@@ -163,18 +164,19 @@ CreateTrigger(CreateTrigStmt *stmt)
 	 * Find and validate the trigger function.
 	 */
 	MemSet(fargtypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
-	tuple = SearchSysCache(PROCNAME,
-						   PointerGetDatum(stmt->funcname),
-						   Int32GetDatum(0),
-						   PointerGetDatum(fargtypes),
-						   0);
+	funcoid = LookupFuncName(stmt->funcname, 0, fargtypes);
+	if (!OidIsValid(funcoid))
+		elog(ERROR, "CreateTrigger: function %s() does not exist",
+			 NameListToString(stmt->funcname));
+	tuple = SearchSysCache(PROCOID,
+						   ObjectIdGetDatum(funcoid),
+						   0, 0, 0);
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "CreateTrigger: function %s() does not exist",
-			 stmt->funcname);
+			 NameListToString(stmt->funcname));
 	if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0)
 		elog(ERROR, "CreateTrigger: function %s() must return OPAQUE",
-			 stmt->funcname);
-	funcoid = tuple->t_data->t_oid;
+			 NameListToString(stmt->funcname));
 	funclang = ((Form_pg_proc) GETSTRUCT(tuple))->prolang;
 	ReleaseSysCache(tuple);
 
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b633b02b79d29bcfee773d80215f2d63c193f0da..873658774ca9acc2cdbbc648ce5b26313e94a1e6 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.175 2002/04/05 11:56:48 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.176 2002/04/09 20:35:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1587,8 +1587,7 @@ _copyFuncCall(FuncCall *from)
 {
 	FuncCall   *newnode = makeNode(FuncCall);
 
-	if (from->funcname)
-		newnode->funcname = pstrdup(from->funcname);
+	Node_Copy(from, newnode, funcname);
 	Node_Copy(from, newnode, args);
 	newnode->agg_star = from->agg_star;
 	newnode->agg_distinct = from->agg_distinct;
@@ -1719,6 +1718,7 @@ _copyIndexElem(IndexElem *from)
 
 	if (from->name)
 		newnode->name = pstrdup(from->name);
+	Node_Copy(from, newnode, funcname);
 	Node_Copy(from, newnode, args);
 	if (from->class)
 		newnode->class = pstrdup(from->class);
@@ -1940,8 +1940,7 @@ _copyFuncWithArgs(FuncWithArgs *from)
 {
 	FuncWithArgs *newnode = makeNode(FuncWithArgs);
 
-	if (from->funcname)
-		newnode->funcname = pstrdup(from->funcname);
+	Node_Copy(from, newnode, funcname);
 	Node_Copy(from, newnode, funcargs);
 
 	return newnode;
@@ -2052,13 +2051,10 @@ _copyCommentStmt(CommentStmt *from)
 	CommentStmt *newnode = makeNode(CommentStmt);
 
 	newnode->objtype = from->objtype;
-	if (from->objschema)
-		newnode->objschema = pstrdup(from->objschema);
-	newnode->objname = pstrdup(from->objname);
-	if (from->objproperty)
-		newnode->objproperty = pstrdup(from->objproperty);
-	Node_Copy(from, newnode, objlist);
-	newnode->comment = pstrdup(from->comment);
+	Node_Copy(from, newnode, objname);
+	Node_Copy(from, newnode, objargs);
+	if (from->comment)
+		newnode->comment = pstrdup(from->comment);
 
 	return newnode;
 }
@@ -2114,7 +2110,7 @@ _copyRemoveAggrStmt(RemoveAggrStmt *from)
 {
 	RemoveAggrStmt *newnode = makeNode(RemoveAggrStmt);
 
-	newnode->aggname = pstrdup(from->aggname);
+	Node_Copy(from, newnode, aggname);
 	Node_Copy(from, newnode, aggtype);
 
 	return newnode;
@@ -2125,7 +2121,7 @@ _copyRemoveFuncStmt(RemoveFuncStmt *from)
 {
 	RemoveFuncStmt *newnode = makeNode(RemoveFuncStmt);
 
-	newnode->funcname = pstrdup(from->funcname);
+	Node_Copy(from, newnode, funcname);
 	Node_Copy(from, newnode, args);
 
 	return newnode;
@@ -2370,8 +2366,7 @@ _copyCreateTrigStmt(CreateTrigStmt *from)
 	if (from->trigname)
 		newnode->trigname = pstrdup(from->trigname);
 	Node_Copy(from, newnode, relation);
-	if (from->funcname)
-		newnode->funcname = pstrdup(from->funcname);
+	Node_Copy(from, newnode, funcname);
 	Node_Copy(from, newnode, args);
 	newnode->before = from->before;
 	newnode->row = from->row;
@@ -2411,8 +2406,7 @@ _copyCreatePLangStmt(CreatePLangStmt *from)
 
 	if (from->plname)
 		newnode->plname = pstrdup(from->plname);
-	if (from->plhandler)
-		newnode->plhandler = pstrdup(from->plhandler);
+	Node_Copy(from, newnode, plhandler);
 	if (from->plcompiler)
 		newnode->plcompiler = pstrdup(from->plcompiler);
 	newnode->pltrusted = from->pltrusted;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index eceb8cb36f796e0aa0acb660dac9f6e8df433a51..9458ebc5b95568daf03dc25089151198f2e52867 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.123 2002/04/05 11:56:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.124 2002/04/09 20:35:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -769,7 +769,7 @@ _equalPrivGrantee(PrivGrantee *a, PrivGrantee *b)
 static bool
 _equalFuncWithArgs(FuncWithArgs *a, FuncWithArgs *b)
 {
-	return equalstr(a->funcname, b->funcname)
+	return equal(a->funcname, b->funcname)
 		&& equal(a->funcargs, b->funcargs);
 }
 
@@ -877,13 +877,9 @@ _equalCommentStmt(CommentStmt *a, CommentStmt *b)
 {
 	if (a->objtype != b->objtype)
 		return false;
-	if (!equalstr(a->objname, b->objname))
+	if (!equal(a->objname, b->objname))
 		return false;
-	if (!equalstr(a->objschema, b->objschema))
-		return false;
-	if (!equalstr(a->objproperty, b->objproperty))
-		return false;
-	if (!equal(a->objlist, b->objlist))
+	if (!equal(a->objargs, b->objargs))
 		return false;
 	if (!equalstr(a->comment, b->comment))
 		return false;
@@ -953,7 +949,7 @@ _equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b)
 static bool
 _equalRemoveAggrStmt(RemoveAggrStmt *a, RemoveAggrStmt *b)
 {
-	if (!equalstr(a->aggname, b->aggname))
+	if (!equal(a->aggname, b->aggname))
 		return false;
 	if (!equal(a->aggtype, b->aggtype))
 		return false;
@@ -964,7 +960,7 @@ _equalRemoveAggrStmt(RemoveAggrStmt *a, RemoveAggrStmt *b)
 static bool
 _equalRemoveFuncStmt(RemoveFuncStmt *a, RemoveFuncStmt *b)
 {
-	if (!equalstr(a->funcname, b->funcname))
+	if (!equal(a->funcname, b->funcname))
 		return false;
 	if (!equal(a->args, b->args))
 		return false;
@@ -1207,7 +1203,7 @@ _equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
 		return false;
 	if (!equal(a->relation, b->relation))
 		return false;
-	if (!equalstr(a->funcname, b->funcname))
+	if (!equal(a->funcname, b->funcname))
 		return false;
 	if (!equal(a->args, b->args))
 		return false;
@@ -1253,7 +1249,7 @@ _equalCreatePLangStmt(CreatePLangStmt *a, CreatePLangStmt *b)
 {
 	if (!equalstr(a->plname, b->plname))
 		return false;
-	if (!equalstr(a->plhandler, b->plhandler))
+	if (!equal(a->plhandler, b->plhandler))
 		return false;
 	if (!equalstr(a->plcompiler, b->plcompiler))
 		return false;
@@ -1463,7 +1459,7 @@ _equalIdent(Ident *a, Ident *b)
 static bool
 _equalFuncCall(FuncCall *a, FuncCall *b)
 {
-	if (!equalstr(a->funcname, b->funcname))
+	if (!equal(a->funcname, b->funcname))
 		return false;
 	if (!equal(a->args, b->args))
 		return false;
@@ -1601,6 +1597,8 @@ _equalIndexElem(IndexElem *a, IndexElem *b)
 {
 	if (!equalstr(a->name, b->name))
 		return false;
+	if (!equal(a->funcname, b->funcname))
+		return false;
 	if (!equal(a->args, b->args))
 		return false;
 	if (!equalstr(a->class, b->class))
diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c
index 9b588150fda8be7757d8345626164ef383f7be59..a61991f38fa015aa095b52f4b407eeb74f8aee69 100644
--- a/src/backend/nodes/list.c
+++ b/src/backend/nodes/list.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.39 2001/03/22 03:59:32 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.40 2002/04/09 20:35:50 tgl Exp $
  *
  * NOTES
  *	  XXX a few of the following functions are duplicated to handle
@@ -233,6 +233,36 @@ length(List *l)
 	return i;
 }
 
+/*
+ *	llast
+ *
+ *	Get the last element of l ... error if empty list
+ */
+void *
+llast(List *l)
+{
+	if (l == NIL)
+		elog(ERROR, "llast: empty list");
+	while (lnext(l) != NIL)
+		l = lnext(l);
+	return lfirst(l);
+}
+
+/*
+ *	llasti
+ *
+ *	As above, but for integer lists
+ */
+int
+llasti(List *l)
+{
+	if (l == NIL)
+		elog(ERROR, "llasti: empty list");
+	while (lnext(l) != NIL)
+		l = lnext(l);
+	return lfirsti(l);
+}
+
 /*
  *	freeList
  *
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 20d25c6439785068389070b7128b2d689f8e61a9..a495f5ed10b3e42cb7336d9f720014d94ac40dc0 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -5,7 +5,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/nodes/outfuncs.c,v 1.152 2002/03/29 19:06:09 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.153 2002/04/09 20:35:50 tgl Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -160,7 +160,7 @@ static void
 _outFuncCall(StringInfo str, FuncCall *node)
 {
 	appendStringInfo(str, "FUNCTION ");
-	_outToken(str, node->funcname);
+	_outNode(str, node->funcname);
 	appendStringInfo(str, " :args ");
 	_outNode(str, node->args);
 	appendStringInfo(str, " :agg_star %s :agg_distinct %s ",
@@ -213,6 +213,8 @@ _outIndexElem(StringInfo str, IndexElem *node)
 {
 	appendStringInfo(str, " INDEXELEM :name ");
 	_outToken(str, node->name);
+	appendStringInfo(str, " :funcname ");
+	_outNode(str, node->funcname);
 	appendStringInfo(str, " :args ");
 	_outNode(str, node->args);
 	appendStringInfo(str, " :class ");
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 0de9c5bb851b86f1bf2f87d5ebaec9518b90a1a5..8b3f218b83adc7d987c95f949ab254feb0fed4b3 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 6ba8766e1ac173cfe40c5e4c750a7ed3fbdd97e0..3488fb0762ff3a6af8589eddb9f12b727558359f 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 dc939a71801e129102ab62bd44bf5dbf35e7fec6..3812579a4dbbc9ec41380c8ad1507d80f04974ac 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 690a047915ac202cfb32e4aabe6fe99cd1c288a5..4dd5777e1e11f6c9b5ddd01f4d0961d258f43dc4 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 2a5a7698d858fd0c4705785a663870784b2afa6d..f84497160613e6e6bb47cbc92ea951a083f8d507 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 578402fd255293543a98abaa3275fa5444498b2c..a86195126ffafc29dcb6ab59ebd6c26d8492d8b5 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 e8e82a45c3b9d09ee65388eab049546bae5eed50..83c53de5d1d7aeea8c25646fdc4e15dfccb2d8bd 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;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index bd5e31666ca9c70c8489fccbcd2b98303b551d95..ed87b00b75783e2ea5b010783267444164cbc64b 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.145 2002/04/01 04:35:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.146 2002/04/09 20:35:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -345,12 +345,7 @@ ProcessUtility(Node *parsetree,
 			break;
 
 		case T_CommentStmt:
-			{
-				CommentStmt *stmt = (CommentStmt *) parsetree;
-
-				CommentObject(stmt->objtype, stmt->objschema, stmt->objname,
-							  stmt->objproperty, stmt->objlist, stmt->comment);
-			}
+			CommentObject((CommentStmt *) parsetree);
 			break;
 
 		case T_CopyStmt:
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 7e6a95a324e464a932a7855edec6c0e037057f3d..36535bd7fa92d70764bb0b0e330a12b57c0e73ed 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.74 2002/04/06 06:59:23 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.75 2002/04/09 20:35:54 tgl Exp $
  *
  * NOTES
  *	  These routines allow the parser/planner/executor to perform
@@ -303,15 +303,15 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0
 	}},
-	{ProcedureRelationName,		/* PROCNAME */
-		ProcedureNameNspIndex,	/* XXX very temporary */
+	{ProcedureRelationName,		/* PROCNAMENSP */
+		ProcedureNameNspIndex,
 		0,
-		3,
+		4,
 		{
 			Anum_pg_proc_proname,
 			Anum_pg_proc_pronargs,
 			Anum_pg_proc_proargtypes,
-			0
+			Anum_pg_proc_pronamespace
 	}},
 	{ProcedureRelationName,		/* PROCOID */
 		ProcedureOidIndex,
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 4c81e78f3ffbe3699bf638798a7ec84679a46046..15a21e77d5d76b3193526cb3f27bbdaf068bc93e 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: namespace.h,v 1.6 2002/04/06 06:59:24 tgl Exp $
+ * $Id: namespace.h,v 1.7 2002/04/09 20:35:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,6 +47,8 @@ extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p);
 
 extern RangeVar *makeRangeVarFromNameList(List *names);
 
+extern char *NameListToString(List *names);
+
 extern bool isTempNamespace(Oid namespaceId);
 
 /* stuff for search_path GUC variable */
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 65494e8afe200fe83d7489414196c2069dc1299f..3d44f4c4c0fb6389cddc3891e7a30ecd0bb2093a 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_aggregate.h,v 1.36 2002/03/29 19:06:18 tgl Exp $
+ * $Id: pg_aggregate.h,v 1.37 2002/04/09 20:35:54 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -157,8 +157,8 @@ DATA(insert OID = 0 ( stddev	PGUID numeric_accum  numeric_stddev		1700 1231 1700
  */
 extern void AggregateCreate(const char *aggName,
 							Oid aggNamespace,
-							char *aggtransfnName,
-							char *aggfinalfnName,
+							List *aggtransfnName,
+							List *aggfinalfnName,
 							Oid aggBaseType,
 							Oid aggTransType,
 							const char *agginitval);
diff --git a/src/include/commands/comment.h b/src/include/commands/comment.h
index f1e9a760b0b08f60f61b9ecb1e0b31acbe01ca34..bf2acfcfa0ed9479f862b2247b0749b179c4a09f 100644
--- a/src/include/commands/comment.h
+++ b/src/include/commands/comment.h
@@ -12,7 +12,7 @@
 #ifndef COMMENT_H
 #define COMMENT_H
 
-#include "nodes/pg_list.h"
+#include "nodes/parsenodes.h"
 
 /*------------------------------------------------------------------
  * Function Prototypes --
@@ -25,8 +25,7 @@
  *------------------------------------------------------------------
  */
 
-extern void CommentObject(int objtype, char * schemaname, char *objname,
-							char *objproperty, List *objlist, char *comment);
+extern void CommentObject(CommentStmt *stmt);
 
 extern void DeleteComments(Oid oid, Oid classoid);
 
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 69f180ec1622e9afe80796a77882ec390fcfcd9c..83b8fec6d77cb05cc6e06f9561186fcf7231181d 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: defrem.h,v 1.33 2002/03/29 19:06:22 tgl Exp $
+ * $Id: defrem.h,v 1.34 2002/04/09 20:35:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,10 +45,10 @@ extern void DefineDomain(CreateDomainStmt *stmt);
  * prototypes in remove.c
  */
 extern void RemoveDomain(List *names, int behavior);
-extern void RemoveFunction(char *functionName, List *argTypes);
+extern void RemoveFunction(List *functionName, List *argTypes);
 extern void RemoveOperator(char *operatorName,
 			   TypeName *typeName1, TypeName *typeName2);
 extern void RemoveType(List *names);
-extern void RemoveAggregate(char *aggName, TypeName *aggType);
+extern void RemoveAggregate(List *aggName, TypeName *aggType);
 
 #endif   /* DEFREM_H */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index e2b0d9f38f3d43b1d060a16d732e8e1814890a1a..6fc2fec9ad952d677b1edcc36e5f269465eaf1f1 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.168 2002/04/05 11:56:54 momjian Exp $
+ * $Id: parsenodes.h,v 1.169 2002/04/09 20:35:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -304,7 +304,7 @@ typedef struct Ident
 typedef struct FuncCall
 {
 	NodeTag		type;
-	char	   *funcname;		/* name of function */
+	List	   *funcname;		/* qualified name of function */
 	List	   *args;			/* the arguments (list of exprs) */
 	bool		agg_star;		/* argument was really '*' */
 	bool		agg_distinct;	/* arguments were labeled DISTINCT */
@@ -390,15 +390,16 @@ typedef struct RangeSubselect
 /*
  * IndexElem - index parameters (used in CREATE INDEX)
  *
- * For a plain index, each 'name' is an attribute name in the heap relation,
- * and 'args' is NIL.  For a functional index, only one IndexElem is allowed.
- * It has name = name of function and args = list of attribute names that
- * are the function's arguments.
+ * For a plain index, each 'name' is an attribute name in the heap relation;
+ * 'funcname' and 'args' are NIL.  For a functional index, only one IndexElem
+ * is allowed.  It has name = NULL, funcname = name of function and args =
+ * list of attribute names that are the function's arguments.
  */
 typedef struct IndexElem
 {
 	NodeTag		type;
-	char	   *name;			/* name of attribute to index, or function */
+	char	   *name;			/* name of attribute to index, or NULL */
+	List	   *funcname;		/* qualified name of function */
 	List	   *args;			/* list of names of function arguments */
 	char	   *class;			/* name of desired opclass; NULL = default */
 } IndexElem;
@@ -780,7 +781,7 @@ typedef struct PrivGrantee
 typedef struct FuncWithArgs
 {
 	NodeTag		type;
-	char	   *funcname;
+	List	   *funcname;		/* qualified name of function */
 	List	   *funcargs;		/* list of Typename nodes */
 } FuncWithArgs;
 
@@ -919,10 +920,10 @@ typedef struct FkConstraint
 typedef struct CreateTrigStmt
 {
 	NodeTag		type;
-	char	   *trigname;		/* TRIGGER' name */
-	RangeVar   *relation;		/* triggered relation */
-	char	   *funcname;		/* function to call (or NULL) */
-	List	   *args;			/* list of (T_String) Values or NULL */
+	char	   *trigname;		/* TRIGGER's name */
+	RangeVar   *relation;		/* relation trigger is on */
+	List	   *funcname;		/* qual. name of function to call */
+	List	   *args;			/* list of (T_String) Values or NIL */
 	bool		before;			/* BEFORE/AFTER */
 	bool		row;			/* ROW/STATEMENT */
 	char		actions[4];		/* Insert, Update, Delete */
@@ -954,7 +955,7 @@ typedef struct CreatePLangStmt
 {
 	NodeTag		type;
 	char	   *plname;			/* PL name */
-	char	   *plhandler;		/* PL call handler function */
+	List	   *plhandler;		/* PL call handler function (qual. name) */
 	char	   *plcompiler;		/* lancompiler text */
 	bool		pltrusted;		/* PL is trusted */
 } CreatePLangStmt;
@@ -1097,12 +1098,9 @@ typedef struct CommentStmt
 {
 	NodeTag		type;
 	int			objtype;		/* Object's type */
-	char	   *objschema;		/* Schema where object is defined,
-								 * if object is schema specific */
-	char	   *objname;		/* Name of the object */
-	char	   *objproperty;	/* Property Id (such as column) */
-	List	   *objlist;		/* Arguments for VAL objects */
-	char	   *comment;		/* The comment to insert */
+	List	   *objname;		/* Qualified name of the object */
+	List	   *objargs;		/* Arguments if needed (eg, for functions) */
+	char	   *comment;		/* Comment to insert, or NULL to remove */
 } CommentStmt;
 
 /* ----------------------
@@ -1154,7 +1152,7 @@ typedef struct ProcedureStmt
 {
 	NodeTag		type;
 	bool		replace;		/* T => replace if already exists */
-	List	   *funcname;		/* name of function to create */
+	List	   *funcname;		/* qualified name of function to create */
 	List	   *argTypes;		/* list of argument types (TypeName nodes) */
 	TypeName   *returnType;		/* the return type */
 	List	   *withClause;		/* a list of DefElem */
@@ -1169,7 +1167,7 @@ typedef struct ProcedureStmt
 typedef struct RemoveAggrStmt
 {
 	NodeTag		type;
-	char	   *aggname;		/* aggregate to drop */
+	List	   *aggname;		/* aggregate to drop */
 	TypeName   *aggtype;		/* TypeName for input datatype, or NULL */
 } RemoveAggrStmt;
 
@@ -1180,7 +1178,7 @@ typedef struct RemoveAggrStmt
 typedef struct RemoveFuncStmt
 {
 	NodeTag		type;
-	char	   *funcname;		/* function to drop */
+	List	   *funcname;		/* function to drop */
 	List	   *args;			/* types of the arguments */
 } RemoveFuncStmt;
 
diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h
index 6b224d6c3859b189d8d1af989222a999c09d56b8..722fb772916a404e04c387b908c5930ed8130856 100644
--- a/src/include/nodes/pg_list.h
+++ b/src/include/nodes/pg_list.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_list.h,v 1.26 2001/11/05 17:46:34 momjian Exp $
+ * $Id: pg_list.h,v 1.27 2002/04/09 20:35:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -109,6 +109,8 @@ typedef struct List
  * function prototypes in nodes/list.c
  */
 extern int	length(List *list);
+extern void *llast(List *list);
+extern int	llasti(List *list);
 extern List *nconc(List *list1, List *list2);
 extern List *lcons(void *datum, List *list);
 extern List *lconsi(int datum, List *list);
diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h
index a9932ab59a041d184f764af8e56dece2b602df5f..42ae42d9e63b084e5d3db3fb6f2821d71d197e3a 100644
--- a/src/include/parser/gramparse.h
+++ b/src/include/parser/gramparse.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: gramparse.h,v 1.19 2001/11/05 17:46:34 momjian Exp $
+ * $Id: gramparse.h,v 1.20 2002/04/09 20:35:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,6 +29,7 @@ extern Oid	param_type(int t);
 extern int	yyparse(void);
 extern char *xlateSqlFunc(char *name);
 extern char *xlateSqlType(char *name);
+extern List *SystemFuncName(char *name);
 bool		exprIsNullConstant(Node *arg);
 
 #endif   /* GRAMPARSE_H */
diff --git a/src/include/parser/parse_agg.h b/src/include/parser/parse_agg.h
index 666e4ede7645706e5b8acc3b434534bba5956b0f..03ac8dc64622e243829dbab8cf41bfadaa2b67db 100644
--- a/src/include/parser/parse_agg.h
+++ b/src/include/parser/parse_agg.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_agg.h,v 1.21 2002/03/21 16:01:55 tgl Exp $
+ * $Id: parse_agg.h,v 1.22 2002/04/09 20:35:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,8 +18,8 @@
 
 extern void AddAggToParseState(ParseState *pstate, Aggref *aggref);
 extern void parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual);
-extern Aggref *ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
+extern Aggref *ParseAgg(ParseState *pstate, List *aggname, Oid basetype,
 		 List *args, bool agg_star, bool agg_distinct);
-extern void agg_error(char *caller, char *aggname, Oid basetypeID);
+extern void agg_error(const char *caller, List *aggname, Oid basetypeID);
 
 #endif   /* PARSE_AGG_H */
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
index 01e5b16e2b5d54a88c91a8c44778263559726471..3a7641e1de7a18d4deb127fe8a261145392cc435 100644
--- a/src/include/parser/parse_func.h
+++ b/src/include/parser/parse_func.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_func.h,v 1.37 2002/03/29 19:06:24 tgl Exp $
+ * $Id: parse_func.h,v 1.38 2002/04/09 20:35:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,18 +48,22 @@ typedef enum
 
 
 extern Node *ParseFuncOrColumn(ParseState *pstate,
-				  char *funcname, List *fargs,
+				  List *funcname, List *fargs,
 				  bool agg_star, bool agg_distinct, bool is_column);
 
-extern FuncDetailCode func_get_detail(char *funcname, List *fargs,
+extern FuncDetailCode func_get_detail(List *funcname, List *fargs,
 				int nargs, Oid *argtypes,
 				Oid *funcid, Oid *rettype,
 				bool *retset, Oid **true_typeids);
 
 extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
 
-extern void func_error(const char *caller, const char *funcname,
+extern void func_error(const char *caller, List *funcname,
 					   int nargs, const Oid *argtypes,
 					   const char *msg);
 
+extern Oid	LookupFuncName(List *funcname, int nargs, const Oid *argtypes);
+extern Oid	LookupFuncNameTypeNames(List *funcname, List *argtypes,
+									bool opaqueOK, const char *caller);
+
 #endif   /* PARSE_FUNC_H */
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 1d9ddd9acfd8f37173802ac48e0889947c4f0d08..365d9efdb5d4d92bbdd514b7a85f0ea77e77b0c9 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: syscache.h,v 1.42 2002/04/06 06:59:25 tgl Exp $
+ * $Id: syscache.h,v 1.43 2002/04/09 20:35:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,7 +49,7 @@
 #define NAMESPACEOID	18
 #define OPERNAME		19
 #define OPEROID			20
-#define PROCNAME		21
+#define PROCNAMENSP		21
 #define PROCOID			22
 #define RELNAMENSP		23
 #define RELOID			24
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 6c9b84dda2b8f56a4d63deec162b66c41300679d..ab4db0d93ef345673bfaaad954b30ce7f6dc0423 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -205,7 +205,7 @@ GRANT USAGE ON FUNCTION testfunc1(int) TO regressuser3; -- semantic error
 ERROR:  invalid privilege type USAGE for function object
 GRANT ALL PRIVILEGES ON FUNCTION testfunc1(int) TO regressuser4;
 GRANT ALL PRIVILEGES ON FUNCTION testfunc_nosuch(int) TO regressuser4;
-ERROR:  Function 'testfunc_nosuch(int4)' does not exist
+ERROR:  GRANT: function 'testfunc_nosuch(int4)' does not exist
 SET SESSION AUTHORIZATION regressuser2;
 SELECT testfunc1(5), testfunc2(5); -- ok
  testfunc1 | testfunc2