*** ./src/backend/commands/define.c.orig	Mon Sep 13 14:30:58 1999
--- ./src/backend/commands/define.c	Mon Sep 13 15:53:47 1999
***************
*** 178,200 ****
  }
  
  
  
  static void
! interpret_AS_clause(const char *languageName, const char *as,
  					char **prosrc_str_p, char **probin_str_p)
  {
  
  	if (strcmp(languageName, "C") == 0)
  	{
! 		/* For "C" language, store the given string in probin */
! 		*prosrc_str_p = "-";
! 		*probin_str_p = (char *) as;
  	}
  	else
  	{
! 		/* Everything else wants the given string in prosrc */
! 		*prosrc_str_p = (char *) as;
  		*probin_str_p = "-";
  	}
  }
  
--- 178,222 ----
  }
  
  
+ /*
+  * For a dynamically linked C language object, the form of the clause is
+  *
+  *	   AS <object file name> [, <link symbol name> ]
+  *
+  * In all other cases
+  *
+  *	   AS <object reference, or sql code>
+  *
+  */
  
  static void
! interpret_AS_clause(const char *languageName, const List *as,
  					char **prosrc_str_p, char **probin_str_p)
  {
+ 	Assert(as != NIL);
  
  	if (strcmp(languageName, "C") == 0)
  	{
! 
! 		/*
! 		 * For "C" language, store the file name in probin and, when
! 		 * given, the link symbol name in prosrc.
! 		 */
! 		*probin_str_p = strVal(lfirst(as));
! 		if (lnext(as) == NULL)
! 			*prosrc_str_p = "-";
! 		else
! 			*prosrc_str_p = strVal(lsecond(as));
  	}
  	else
  	{
! 		/* Everything else wants the given string in prosrc. */
! 		*prosrc_str_p = strVal(lfirst(as));
  		*probin_str_p = "-";
+ 
+ 		if (lnext(as) != NULL)
+ 			elog(ERROR, "CREATE FUNCTION: parse error in 'AS %s, %s'.",
+ 				 strVal(lfirst(as)), strVal(lsecond(as)));
  	}
  }
  
*** ./src/backend/parser/gram.y.orig	Mon Sep 13 13:25:57 1999
--- ./src/backend/parser/gram.y	Mon Sep 13 14:00:18 1999
***************
*** 162,168 ****
  %type <list>	stmtblock, stmtmulti,
  		result, relation_name_list, OptTableElementList,
  		OptInherit, definition,
! 		opt_with, func_args, func_args_list,
  		oper_argtypes, RuleActionList, RuleActionBlock, RuleActionMulti,
  		opt_column_list, columnList, opt_va_list, va_list,
  		sort_clause, sortby_list, index_params, index_list, name_list,
--- 162,168 ----
  %type <list>	stmtblock, stmtmulti,
  		result, relation_name_list, OptTableElementList,
  		OptInherit, definition,
! 		opt_with, func_args, func_args_list, func_as,
  		oper_argtypes, RuleActionList, RuleActionBlock, RuleActionMulti,
  		opt_column_list, columnList, opt_va_list, va_list,
  		sort_clause, sortby_list, index_params, index_list, name_list,
***************
*** 1907,1913 ****
   *****************************************************************************/
  
  ProcedureStmt:	CREATE FUNCTION func_name func_args
! 			 RETURNS func_return opt_with AS Sconst LANGUAGE Sconst
  				{
  					ProcedureStmt *n = makeNode(ProcedureStmt);
  					n->funcname = $3;
--- 1907,1913 ----
   *****************************************************************************/
  
  ProcedureStmt:	CREATE FUNCTION func_name func_args
! 			 RETURNS func_return opt_with AS func_as LANGUAGE Sconst
  				{
  					ProcedureStmt *n = makeNode(ProcedureStmt);
  					n->funcname = $3;
***************
*** 1931,1936 ****
--- 1931,1942 ----
  				{	$$ = lcons(makeString($1),NIL); }
  		| func_args_list ',' TypeId
  				{	$$ = lappend($1,makeString($3)); }
+ 		;
+ 
+ func_as: Sconst	
+ 				{   $$ = lcons(makeString($1),NIL); }
+ 		| Sconst ',' Sconst
+ 				{ 	$$ = lappend(lcons(makeString($1),NIL), makeString($3)); }
  		;
  
  func_return:  set_opt TypeId
*** ./src/backend/utils/fmgr/dfmgr.c.orig	Mon Sep 13 13:25:57 1999
--- ./src/backend/utils/fmgr/dfmgr.c	Mon Sep 13 15:57:47 1999
***************
*** 42,49 ****
  	HeapTuple	procedureTuple;
  	Form_pg_proc procedureStruct;
  	char	   *proname,
! 			   *probinstring;
  	Datum		probinattr;
  	func_ptr	user_fn;
  	Relation	rel;
  	bool		isnull;
--- 42,52 ----
  	HeapTuple	procedureTuple;
  	Form_pg_proc procedureStruct;
  	char	   *proname,
! 			   *probinstring,
! 			   *prosrcstring,
! 			   *linksymbol;
  	Datum		probinattr;
+ 	Datum		prosrcattr;
  	func_ptr	user_fn;
  	Relation	rel;
  	bool		isnull;
***************
*** 99,105 ****
  	}
  	probinstring = textout((struct varlena *) probinattr);
  
! 	user_fn = handle_load(probinstring, proname);
  
  	procedureId_save = procedureId;
  	user_fn_save = user_fn;
--- 102,133 ----
  	}
  	probinstring = textout((struct varlena *) probinattr);
  
! 	prosrcattr = heap_getattr(procedureTuple,
! 							  Anum_pg_proc_prosrc,
! 							  RelationGetDescr(rel), &isnull);
! 
! 	if (isnull)
! 	{							/* Use the proname for the link symbol */
! 		linksymbol = proname;
! 	}
! 	else if (!PointerIsValid(prosrcattr))
! 	{							/* pg_proc must be messed up! */
! 		heap_close(rel);
! 		elog(ERROR, "fmgr: Could not extract prosrc for %u from %s",
! 			 procedureId, ProcedureRelationName);
! 		return (func_ptr) NULL;
! 	}
! 	else
! 	{							/* The text in prosrcattr is either "-" or
! 								 * a link symbol */
! 		prosrcstring = textout((struct varlena *) prosrcattr);
! 		if (strcmp(prosrcstring, "-") == 0)
! 			linksymbol = proname;
! 		else
! 			linksymbol = prosrcstring;
! 	}
! 
! 	user_fn = handle_load(probinstring, linksymbol);
  
  	procedureId_save = procedureId;
  	user_fn_save = user_fn;
*** ./src/include/nodes/parsenodes.h.orig	Mon Sep 13 13:25:58 1999
--- ./src/include/nodes/parsenodes.h	Mon Sep 13 15:59:26 1999
***************
*** 70,76 ****
  	/* internal to planner */
  	List	   *base_rel_list;	/* list of base-relation RelOptInfos */
  	List	   *join_rel_list;	/* list of join-relation RelOptInfos */
! 	List	   *query_pathkeys;	/* pathkeys for query_planner()'s result */
  } Query;
  
  
--- 70,76 ----
  	/* internal to planner */
  	List	   *base_rel_list;	/* list of base-relation RelOptInfos */
  	List	   *join_rel_list;	/* list of join-relation RelOptInfos */
! 	List	   *query_pathkeys; /* pathkeys for query_planner()'s result */
  } Query;
  
  
***************
*** 351,357 ****
  	Node	   *returnType;		/* the return type (as a string or a
  								 * TypeName (ie.setof) */
  	List	   *withClause;		/* a list of ParamString */
! 	char	   *as;				/* the SQL statement or filename */
  	char	   *language;		/* C or SQL */
  } ProcedureStmt;
  
--- 351,357 ----
  	Node	   *returnType;		/* the return type (as a string or a
  								 * TypeName (ie.setof) */
  	List	   *withClause;		/* a list of ParamString */
! 	List	   *as;				/* the SQL statement or filename */
  	char	   *language;		/* C or SQL */
  } ProcedureStmt;
  
***************
*** 826,833 ****
  {
  	NodeTag		type;
  	char	   *name;			/* column name or NULL */
! 	List	   *indirection;	/* subscripts for destination column, or NIL */
! 	Node	   *val;			/* the value expression to compute or assign */
  } ResTarget;
  
  /*
--- 826,835 ----
  {
  	NodeTag		type;
  	char	   *name;			/* column name or NULL */
! 	List	   *indirection;	/* subscripts for destination column, or
! 								 * NIL */
! 	Node	   *val;			/* the value expression to compute or
! 								 * assign */
  } ResTarget;
  
  /*
***************
*** 960,966 ****
  typedef struct SortClause
  {
  	NodeTag		type;
! 	Index		tleSortGroupRef; /* reference into targetlist */
  	Oid			sortop;			/* the sort operator to use */
  } SortClause;
  
--- 962,968 ----
  typedef struct SortClause
  {
  	NodeTag		type;
! 	Index		tleSortGroupRef;/* reference into targetlist */
  	Oid			sortop;			/* the sort operator to use */
  } SortClause;
  
*** ./src/interfaces/ecpg/preproc/preproc.y.orig	Mon Sep 13 13:25:58 1999
--- ./src/interfaces/ecpg/preproc/preproc.y	Mon Sep 13 14:57:40 1999
***************
*** 799,805 ****
  %type  <str>    opt_analyze opt_va_list va_list ExplainStmt index_params
  %type  <str>    index_list func_index index_elem opt_type opt_class access_method_clause
  %type  <str>    index_opt_unique IndexStmt set_opt func_return def_rest
! %type  <str>    func_args_list func_args opt_with ProcedureStmt def_arg
  %type  <str>    def_elem def_list definition def_name def_type DefineStmt
  %type  <str>    opt_instead event event_object RuleActionList,
  %type  <str>	RuleActionBlock RuleActionMulti join_list
--- 799,805 ----
  %type  <str>    opt_analyze opt_va_list va_list ExplainStmt index_params
  %type  <str>    index_list func_index index_elem opt_type opt_class access_method_clause
  %type  <str>    index_opt_unique IndexStmt set_opt func_return def_rest
! %type  <str>    func_as func_args_list func_args opt_with ProcedureStmt def_arg
  %type  <str>    def_elem def_list definition def_name def_type DefineStmt
  %type  <str>    opt_instead event event_object RuleActionList,
  %type  <str>	RuleActionBlock RuleActionMulti join_list
***************
*** 2197,2207 ****
   *						[, iscachable])
   *						[arg is (<type-1> { , <type-n>})]
   *						as <filename or code in language as appropriate>
   *
   *****************************************************************************/
  
  ProcedureStmt:	CREATE FUNCTION func_name func_args
! 			 RETURNS func_return opt_with AS Sconst LANGUAGE Sconst
  				{
  					$$ = cat2_str(cat5_str(cat5_str(make1_str("create function"), $3, $4, make1_str("returns"), $6), $7, make1_str("as"), $9, make1_str("language")), $11);
  				}
--- 2197,2208 ----
   *						[, iscachable])
   *						[arg is (<type-1> { , <type-n>})]
   *						as <filename or code in language as appropriate>
+  *                      [, <link name for dynamic loader>]
   *
   *****************************************************************************/
  
  ProcedureStmt:	CREATE FUNCTION func_name func_args
! 			 RETURNS func_return opt_with AS func_as LANGUAGE Sconst
  				{
  					$$ = cat2_str(cat5_str(cat5_str(make1_str("create function"), $3, $4, make1_str("returns"), $6), $7, make1_str("as"), $9, make1_str("language")), $11);
  				}
***************
*** 2217,2222 ****
--- 2218,2229 ----
  func_args_list:  TypeId				{ $$ = $1; }
  		| func_args_list ',' TypeId
  				{	$$ = cat3_str($1, make1_str(","), $3); }
+ 		;
+ 
+ func_as:  Sconst 
+                 { $$ = $1; }
+         | Sconst ',' Sconst
+ 				{ $$ = cat3_str($1, make1_str(","), $3); }
  		;
  
  func_return:  set_opt TypeId
