diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 509d5026d301a55e73b1872074f95ae779b243f4..2aa197654c7f07e6793b085c3ab2c6f054477786 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.35 1999/09/28 04:34:40 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.36 1999/10/02 21:33:24 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -53,6 +53,7 @@
 #include "utils/syscache.h"
 
 static char *defGetString(DefElem *def);
+static double defGetNumeric(DefElem *def);
 static int	defGetTypeLength(DefElem *def);
 
 #define DEFAULT_TYPDELIM		','
@@ -103,9 +104,8 @@ compute_return_type(const Node *returnType,
 }
 
 
-
 static void
-compute_full_attributes(const List *parameters, int32 *byte_pct_p,
+compute_full_attributes(List *parameters, int32 *byte_pct_p,
 						int32 *perbyte_cpu_p, int32 *percall_cpu_p,
 						int32 *outin_ratio_p, bool *canCache_p)
 {
@@ -113,7 +113,17 @@ compute_full_attributes(const List *parameters, int32 *byte_pct_p,
   Interpret the parameters *parameters and return their contents as
   *byte_pct_p, etc.
 
-  These are the full parameters of a C or internal function.
+  These parameters supply optional information about a function.
+  All have defaults if not specified.
+
+  Note: as of version 6.6, canCache is used (if set, the optimizer's
+  constant-folder is allowed to pre-evaluate the function if all its
+  inputs are constant).  The other four are not used.  They used to be
+  used in the "expensive functions" optimizer, but that's been dead code
+  for a long time.
+
+  Since canCache is useful for any function, we now allow attributes to be
+  supplied for all functions regardless of language.
 ---------------------------------------------------------------------------*/
 	List	   *pl;
 
@@ -122,58 +132,33 @@ compute_full_attributes(const List *parameters, int32 *byte_pct_p,
 	*perbyte_cpu_p = PERBYTE_CPU;
 	*percall_cpu_p = PERCALL_CPU;
 	*outin_ratio_p = OUTIN_RATIO;
+	*canCache_p = false;
 
-	foreach(pl, (List *) parameters)
+	foreach(pl, parameters)
 	{
-		ParamString *param = (ParamString *) lfirst(pl);
+		DefElem *param = (DefElem *) lfirst(pl);
 
-		if (strcasecmp(param->name, "iscachable") == 0)
+		if (strcasecmp(param->defname, "iscachable") == 0)
 			*canCache_p = true;
-		else if (strcasecmp(param->name, "trusted") == 0)
+		else if (strcasecmp(param->defname, "trusted") == 0)
 		{
-
 			/*
 			 * we don't have untrusted functions any more. The 4.2
 			 * implementation is lousy anyway so I took it out. -ay 10/94
 			 */
 			elog(ERROR, "untrusted function has been decommissioned.");
 		}
-		else if (strcasecmp(param->name, "byte_pct") == 0)
-		{
-
-			/*
-			 * * handle expensive function parameters
-			 */
-			*byte_pct_p = atoi(param->val);
-		}
-		else if (strcasecmp(param->name, "perbyte_cpu") == 0)
-		{
-			if (sscanf(param->val, "%d", perbyte_cpu_p) == 0)
-			{
-				int			count;
-				char	   *ptr;
-
-				for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
-					if (*ptr == '!')
-						count++;
-				*perbyte_cpu_p = (int) pow(10.0, (double) count);
-			}
-		}
-		else if (strcasecmp(param->name, "percall_cpu") == 0)
-		{
-			if (sscanf(param->val, "%d", percall_cpu_p) == 0)
-			{
-				int			count;
-				char	   *ptr;
-
-				for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
-					if (*ptr == '!')
-						count++;
-				*percall_cpu_p = (int) pow(10.0, (double) count);
-			}
-		}
-		else if (strcasecmp(param->name, "outin_ratio") == 0)
-			*outin_ratio_p = atoi(param->val);
+		else if (strcasecmp(param->defname, "byte_pct") == 0)
+			*byte_pct_p = (int) defGetNumeric(param);
+		else if (strcasecmp(param->defname, "perbyte_cpu") == 0)
+			*perbyte_cpu_p = (int) defGetNumeric(param);
+		else if (strcasecmp(param->defname, "percall_cpu") == 0)
+			*percall_cpu_p = (int) defGetNumeric(param);
+		else if (strcasecmp(param->defname, "outin_ratio") == 0)
+			*outin_ratio_p = (int) defGetNumeric(param);
+		else
+			elog(NOTICE, "Unrecognized function attribute '%s' ignored",
+				 param->defname);
 	}
 }
 
@@ -215,8 +200,8 @@ interpret_AS_clause(const char *languageName, const List *as,
 		*probin_str_p = "-";
 
 		if (lnext(as) != NULL)
-			elog(ERROR, "CREATE FUNCTION: parse error in 'AS %s, %s'.",
-				 strVal(lfirst(as)), strVal(lsecond(as)));
+			elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language",
+				 languageName);
 	}
 }
 
@@ -246,39 +231,37 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
 	 * or "SQL"
 	 */
 
+	bool		returnsSet;
+	/* The function returns a set of values, as opposed to a singleton. */
+
+	bool		lanisPL = false;
+
 	/*
-	 * The following are attributes of the function, as expressed in the
-	 * CREATE FUNCTION statement, where applicable.
+	 * The following are optional user-supplied attributes of the function.
 	 */
 	int32		byte_pct,
 				perbyte_cpu,
 				percall_cpu,
 				outin_ratio;
 	bool		canCache;
-	bool		returnsSet;
-
-	bool		lanisPL = false;
-
-	/* The function returns a set of values, as opposed to a singleton. */
 
 
 	case_translate_language_name(stmt->language, languageName);
 
-	compute_return_type(stmt->returnType, &prorettype, &returnsSet);
-
 	if (strcmp(languageName, "C") == 0 ||
 		strcmp(languageName, "internal") == 0)
 	{
-		compute_full_attributes(stmt->withClause,
-								&byte_pct, &perbyte_cpu, &percall_cpu,
-								&outin_ratio, &canCache);
+		if (!superuser())
+			elog(ERROR,
+				 "Only users with Postgres superuser privilege are "
+				 "permitted to create a function "
+				 "in the '%s' language.  Others may use the 'sql' language "
+				 "or the created procedural languages.",
+				 languageName);
 	}
 	else if (strcmp(languageName, "sql") == 0)
 	{
-		/* query optimizer groks sql, these are meaningless */
-		perbyte_cpu = percall_cpu = 0;
-		byte_pct = outin_ratio = 100;
-		canCache = false;
+		/* No security check needed for SQL functions */
 	}
 	else
 	{
@@ -321,47 +304,34 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
 		}
 
 		lanisPL = true;
-
-		/*
-		 * These are meaningless
-		 */
-		perbyte_cpu = percall_cpu = 0;
-		byte_pct = outin_ratio = 100;
-		canCache = false;
 	}
 
-	interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
+	compute_return_type(stmt->returnType, &prorettype, &returnsSet);
 
-	if (strcmp(languageName, "sql") != 0 && lanisPL == false && !superuser())
-		elog(ERROR,
-			 "Only users with Postgres superuser privilege are permitted "
-			 "to create a function "
-			 "in the '%s' language.  Others may use the 'sql' language "
-			 "or the created procedural languages.",
-			 languageName);
-	/* Above does not return. */
-	else
-	{
+	compute_full_attributes(stmt->withClause,
+							&byte_pct, &perbyte_cpu, &percall_cpu,
+							&outin_ratio, &canCache);
 
-		/*
-		 * And now that we have all the parameters, and know we're
-		 * permitted to do so, go ahead and create the function.
-		 */
-		ProcedureCreate(stmt->funcname,
-						returnsSet,
-						prorettype,
-						languageName,
-						prosrc_str,		/* converted to text later */
-						probin_str,		/* converted to text later */
-						canCache,
-						true,	/* (obsolete "trusted") */
-						byte_pct,
-						perbyte_cpu,
-						percall_cpu,
-						outin_ratio,
-						stmt->defArgs,
-						dest);
-	}
+	interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
+
+	/*
+	 * And now that we have all the parameters, and know we're
+	 * permitted to do so, go ahead and create the function.
+	 */
+	ProcedureCreate(stmt->funcname,
+					returnsSet,
+					prorettype,
+					languageName,
+					prosrc_str,		/* converted to text later */
+					probin_str,		/* converted to text later */
+					canCache,
+					true,			/* (obsolete "trusted") */
+					byte_pct,
+					perbyte_cpu,
+					percall_cpu,
+					outin_ratio,
+					stmt->defArgs,
+					dest);
 }
 
 
@@ -734,6 +704,25 @@ defGetString(DefElem *def)
 	return strVal(def->arg);
 }
 
+static double
+defGetNumeric(DefElem *def)
+{
+	if (def->arg == NULL)
+		elog(ERROR, "Define: \"%s\" requires a numeric value",
+			 def->defname);
+	switch (nodeTag(def->arg))
+	{
+		case T_Integer:
+			return (double) intVal(def->arg);
+		case T_Float:
+			return floatVal(def->arg);
+		default:
+			elog(ERROR, "Define: \"%s\" requires a numeric value",
+				 def->defname);
+	}
+	return 0;					/* keep compiler quiet */
+}
+
 static int
 defGetTypeLength(DefElem *def)
 {
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 113854311d6aaf22b855fd59077154e7f3241812..5f82c2b532152a03dea0746fa3f4c89ab5509a17 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.11 1999/09/18 19:06:40 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.12 1999/10/02 21:33:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,7 +50,7 @@ static char *GetDefaultOpClass(Oid atttypid);
  *
  * 'attributeList' is a list of IndexElem specifying either a functional
  *		index or a list of attributes to index on.
- * 'parameterList' is a list of ParamString specified in the with clause.
+ * 'parameterList' is a list of DefElem specified in the with clause.
  * 'predicate' is the qual specified in the where clause.
  * 'rangetable' is for the predicate
  *
@@ -116,22 +116,20 @@ DefineIndex(char *heapRelationName,
 	}
 	accessMethodId = tuple->t_data->t_oid;
 
-
 	/*
-	 * Handle parameters [param list is now different (NOT USED, really) -
-	 * ay 10/94]
-	 *
 	 * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
 	 */
 	foreach(pl, parameterList)
 	{
-		ParamString *param = (ParamString *) lfirst(pl);
+		DefElem *param = (DefElem *) lfirst(pl);
 
-		if (!strcasecmp(param->name, "islossy"))
+		if (!strcasecmp(param->defname, "islossy"))
 			lossy = TRUE;
+		else
+			elog(NOTICE, "Unrecognized index attribute '%s' ignored",
+				 param->defname);
 	}
 
-
 	/*
 	 * Convert the partial-index predicate from parsetree form to plan
 	 * form, so it can be readily evaluated during index creation. Note:
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index b6583197be3962902544901404896717d76d0f5f..96f480ea0ca27f5467401df138f5aab53715692b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.104 1999/09/29 16:06:06 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.105 1999/10/02 21:33:21 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -103,7 +103,6 @@ Oid	param_type(int t); /* used in parse_expr.c */
 
 	TypeName			*typnam;
 	DefElem				*defelt;
-	ParamString			*param;
 	SortGroupBy			*sortgroupby;
 	JoinExpr			*joinexpr;
 	IndexElem			*ielem;
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index a69d20a047694c84e7393fd62a91ddc6f477ddf1..15b22bdfa41a6268d27d1567fcdf646f40f7d11e 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.34 1999/09/28 11:27:13 vadim Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.35 1999/10/02 21:33:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,15 +42,16 @@ fmgr_dynamic(Oid procedureId, int *pronargs)
 	HeapTuple	procedureTuple;
 	Form_pg_proc procedureStruct;
 	char	   *proname,
-			   *probinstring,
-			   *prosrcstring,
-			   *linksymbol;
+			   *linksymbol,
+			   *probinstring;
+	char	   *prosrcstring = NULL;
 	Datum		probinattr;
 	Datum		prosrcattr;
 	func_ptr	user_fn;
 	Relation	rel;
 	bool		isnull;
 
+	/* Implement simple one-element cache for function lookups */
 	if (procedureId == procedureId_save)
 	{
 		*pronargs = pronargs_save;
@@ -91,8 +92,6 @@ fmgr_dynamic(Oid procedureId, int *pronargs)
 	}
 	probinstring = textout((struct varlena *) probinattr);
 
-	heap_close(rel, AccessShareLock);
-
 	prosrcattr = heap_getattr(procedureTuple,
 							  Anum_pg_proc_prosrc,
 							  RelationGetDescr(rel), &isnull);
@@ -118,9 +117,12 @@ fmgr_dynamic(Oid procedureId, int *pronargs)
 			linksymbol = prosrcstring;
 	}
 
+	heap_close(rel, AccessShareLock);
+
 	user_fn = handle_load(probinstring, linksymbol);
 
 	pfree(probinstring);
+	if (prosrcstring) pfree(prosrcstring);
 
 	procedureId_save = procedureId;
 	user_fn_save = user_fn;
diff --git a/src/bin/psql/psqlHelp.h b/src/bin/psql/psqlHelp.h
index 63268c2cbd9ee7ffaa02f927175c80df2e2fc4cf..3b39f7b2d8eadc23ef140bbabe907a3645ec7115 100644
--- a/src/bin/psql/psqlHelp.h
+++ b/src/bin/psql/psqlHelp.h
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: psqlHelp.h,v 1.76 1999/09/28 04:34:48 momjian Exp $
+ * $Id: psqlHelp.h,v 1.77 1999/10/02 21:33:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,14 +88,16 @@ static struct _helpStruct QL_HELP[] = {
 		"create a user-defined function",
 	"\
 \tCREATE FUNCTION function_name ([type1, ...typeN]) RETURNS return_type\n\
-\tAS 'sql-queries'|'builtin_function_name'|'object_filename'\n\
-\tLANGUAGE 'sql'|'internal'|'c';\n\
+\t[WITH ( attributes )]\n\
+\tAS 'sql_queries'|'builtin_function_name'|'procedural_commands'\n\
+\tLANGUAGE 'sql'|'internal'|'procedural_language_name';\n\
 \n\
 OR\n\
 \n\
 \tCREATE FUNCTION function_name ([type1, ...typeN]) RETURNS return_type\n\
-\tAS 'object_filename', 'link_symbol'\n\
-\tLANGUAGE 'c';"},
+\t[WITH ( attributes )]\n\
+\tAS 'object_filename' [, 'link_symbol']\n\
+\tLANGUAGE 'C';"},
 	{"create index",
 		"construct an index",
 	"\
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 68d824732447feb70abdf2ab05a5a22551bedd2b..08705ea9f6ebfcc5cce71595f0e00687ea3755ee 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.53 1999/09/29 16:06:23 wieck Exp $
+ * $Id: nodes.h,v 1.54 1999/10/02 21:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -194,7 +194,7 @@ typedef enum NodeTag
 	T_FuncCall,
 	T_A_Indices,
 	T_ResTarget,
-	T_ParamString,
+	T_ParamString,		/* not used anymore */
 	T_RelExpr,
 	T_SortGroupBy,
 	T_RangeVar,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a736c1af67e79a4274eb178d851fc617d1d18fd2..463ea1518e0d92407a4e300d0949da0df94bee7f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.81 1999/09/29 16:06:23 wieck Exp $
+ * $Id: parsenodes.h,v 1.82 1999/10/02 21:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -346,7 +346,7 @@ typedef struct IndexStmt
 	char	   *relname;		/* name of relation to index on */
 	char	   *accessMethod;	/* name of acess methood (eg. btree) */
 	List	   *indexParams;	/* a list of IndexElem */
-	List	   *withClause;		/* a list of ParamString */
+	List	   *withClause;		/* a list of DefElem */
 	Node	   *whereClause;	/* qualifications */
 	List	   *rangetable;		/* range table, filled in by
 								 * transformStmt() */
@@ -367,7 +367,7 @@ typedef struct ProcedureStmt
 								 * (as Value *) */
 	Node	   *returnType;		/* the return type (as a string or a
 								 * TypeName (ie.setof) */
-	List	   *withClause;		/* a list of ParamString */
+	List	   *withClause;		/* a list of DefElem */
 	List	   *as;				/* the SQL statement or filename */
 	char	   *language;		/* C or SQL */
 } ProcedureStmt;
@@ -862,16 +862,6 @@ typedef struct ResTarget
 								 * assign */
 } ResTarget;
 
-/*
- * ParamString - used in WITH clauses
- */
-typedef struct ParamString
-{
-	NodeTag		type;
-	char	   *name;
-	char	   *val;
-} ParamString;
-
 /*
  * RelExpr - relation expressions
  */