*** pgsql/src/backend/catalog/pg_proc.c.orig	2007-11-15 22:14:33.000000000 +0100
--- pgsql/src/backend/catalog/pg_proc.c	2007-11-26 11:23:36.210317000 +0100
***************
*** 33,39 ****
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
! 
  
  Datum		fmgr_internal_validator(PG_FUNCTION_ARGS);
  Datum		fmgr_c_validator(PG_FUNCTION_ARGS);
--- 33,39 ----
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
! #include "parser/parse_callback.h"
  
  Datum		fmgr_internal_validator(PG_FUNCTION_ARGS);
  Datum		fmgr_c_validator(PG_FUNCTION_ARGS);
***************
*** 531,536 ****
--- 531,537 ----
  	Datum		tmp;
  	char	   *prosrc;
  	ErrorContextCallback sqlerrcontext;
+ 	ParserCallbackContext sqlcallbackcontext;
  	bool		haspolyarg;
  	int			i;
  
***************
*** 586,591 ****
--- 587,599 ----
  		sqlerrcontext.previous = error_context_stack;
  		error_context_stack = &sqlerrcontext;
  
+ 		/* Attach parser callback handler */
+ 		sqlcallbackcontext.context = T_ParsingFunctionBody;
+ 		sqlcallbackcontext.context_arg = (void *)funcoid;
+ 		sqlcallbackcontext.callback = sql_parser_callback_handler;
+ 		sqlcallbackcontext.previous = parser_callback_context_stack;
+ 		parser_callback_context_stack = &sqlcallbackcontext;
+ 
  		/*
  		 * We can't do full prechecking of the function definition if there
  		 * are any polymorphic input types, because actual datatypes of
***************
*** 606,611 ****
--- 614,622 ----
  		else
  			querytree_list = pg_parse_query(prosrc);
  
+ 		/* detach this parser callback handler */
+ 		parser_callback_context_stack = sqlcallbackcontext.previous;
+ 
  		error_context_stack = sqlerrcontext.previous;
  	}
  
***************
*** 614,619 ****
--- 625,631 ----
  	PG_RETURN_VOID();
  }
  
+ 
  /*
   * Error context callback for handling errors in SQL function definitions
   */
*** pgsql/src/backend/executor/functions.c.orig	2007-11-15 22:14:34.000000000 +0100
--- pgsql/src/backend/executor/functions.c	2007-11-26 11:23:36.240359600 +0100
***************
*** 22,27 ****
--- 22,28 ----
  #include "funcapi.h"
  #include "parser/parse_coerce.h"
  #include "parser/parse_expr.h"
+ #include "parser/parse_callback.h"
  #include "tcop/tcopprot.h"
  #include "tcop/utility.h"
  #include "utils/builtins.h"
***************
*** 30,36 ****
  #include "utils/syscache.h"
  #include "utils/typcache.h"
  
- 
  /*
   * We have an execution_state record for each query in a function.	Each
   * record contains a plantree for its query.  If the query is currently in
--- 31,36 ----
***************
*** 596,601 ****
--- 596,602 ----
  	MemoryContext oldcontext;
  	SQLFunctionCachePtr fcache;
  	ErrorContextCallback sqlerrcontext;
+ 	ParserCallbackContext sqlcallbackcontext;
  	execution_state *es;
  	Datum		result = 0;
  
***************
*** 614,619 ****
--- 615,627 ----
  	sqlerrcontext.previous = error_context_stack;
  	error_context_stack = &sqlerrcontext;
  
+ 	/* Attach parser callback handler */
+ 	sqlcallbackcontext.context = T_ParsingFunctionBody;
+ 	sqlcallbackcontext.context_arg = (void *)fcinfo->flinfo->fn_oid;
+ 	sqlcallbackcontext.callback = sql_parser_callback_handler;
+ 	sqlcallbackcontext.previous = parser_callback_context_stack;
+ 	parser_callback_context_stack = &sqlcallbackcontext;
+ 
  	/*
  	 * Initialize fcache (build plans) if first time through.
  	 */
***************
*** 691,696 ****
--- 699,707 ----
  			}
  		}
  
+ 		/* detach this parser callback handler */
+ 		parser_callback_context_stack = sqlcallbackcontext.previous;
+ 
  		error_context_stack = sqlerrcontext.previous;
  
  		MemoryContextSwitchTo(oldcontext);
***************
*** 731,736 ****
--- 742,750 ----
  		}
  	}
  
+ 	/* detach this parser callback handler */
+ 	parser_callback_context_stack = sqlcallbackcontext.previous;
+ 
  	error_context_stack = sqlerrcontext.previous;
  
  	MemoryContextSwitchTo(oldcontext);
*** pgsql/src/backend/optimizer/util/clauses.c.orig	2007-11-22 20:09:23.000000000 +0100
--- pgsql/src/backend/optimizer/util/clauses.c	2007-11-26 11:23:36.280416400 +0100
***************
*** 38,43 ****
--- 38,44 ----
  #include "parser/parse_clause.h"
  #include "parser/parse_coerce.h"
  #include "parser/parse_expr.h"
+ #include "parser/parse_callback.h"
  #include "tcop/tcopprot.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
***************
*** 2924,2929 ****
--- 2925,2931 ----
  	MemoryContext oldcxt;
  	MemoryContext mycxt;
  	ErrorContextCallback sqlerrcontext;
+ 	ParserCallbackContext sqlcallbackcontext;
  	List	   *raw_parsetree_list;
  	Query	   *querytree;
  	Node	   *newexpr;
***************
*** 2959,2964 ****
--- 2961,2973 ----
  	sqlerrcontext.previous = error_context_stack;
  	error_context_stack = &sqlerrcontext;
  
+ 	/* Attach parser callback handler */
+ 	sqlcallbackcontext.context = T_ParsingFunctionBody;
+ 	sqlcallbackcontext.context_arg = (void *)funcid;
+ 	sqlcallbackcontext.callback = sql_parser_callback_handler;
+ 	sqlcallbackcontext.previous = parser_callback_context_stack;
+ 	parser_callback_context_stack = &sqlcallbackcontext;
+ 
  	/*
  	 * Make a temporary memory context, so that we don't leak all the stuff
  	 * that parsing might create.
***************
*** 3144,3149 ****
--- 3153,3161 ----
  	newexpr = eval_const_expressions_mutator(newexpr, context);
  	context->active_fns = list_delete_first(context->active_fns);
  
+ 	/* detach this parser callback handler */
+ 	parser_callback_context_stack = sqlcallbackcontext.previous;
+ 
  	error_context_stack = sqlerrcontext.previous;
  
  	return (Expr *) newexpr;
***************
*** 3152,3159 ****
  fail:
  	MemoryContextSwitchTo(oldcxt);
  	MemoryContextDelete(mycxt);
- 	error_context_stack = sqlerrcontext.previous;
  
  	return NULL;
  }
  
--- 3164,3174 ----
  fail:
  	MemoryContextSwitchTo(oldcxt);
  	MemoryContextDelete(mycxt);
  
+ 	/* detach this parser callback handler */
+ 	parser_callback_context_stack = sqlcallbackcontext.previous;
+ 
+ 	error_context_stack = sqlerrcontext.previous;
  	return NULL;
  }
  
*** pgsql/src/backend/parser/parse_callback.c.orig	1970-01-01 01:00:00.000000000 +0100
--- pgsql/src/backend/parser/parse_callback.c	2007-11-28 09:27:07.204611200 +0100
***************
*** 0 ****
--- 1,158 ----
+ /*-------------------------------------------------------------------------
+  *
+  * parse_callback.c
+  *	  Mechanisme to create callbacks from inside the parser
+  *
+  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *	  $PostgreSQL: pgsql/src/backend/parser/parse_callback.c $
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ #include "parser/parse_node.h"
+ #include "parser/parse_callback.h"
+ #include "utils/lsyscache.h"
+ #include "utils/syscache.h"
+ #include "funcapi.h"
+ #include "parser/parse_expr.h"
+ #include "nodes/parsenodes.h"
+ 
+ /* global parser callback handler context stack */
+ ParserCallbackContext *parser_callback_context_stack = NULL;
+ 
+ /* This function can be called from various places within 
+  * the parser to handle custom/language-specific actions.
+  * For example: The handling of referenced function parameters by name.
+  */
+ void parser_do_callback(ParserCallbackActionTag action, void *args)
+ {
+ 	ParserCallbackContext *ctx;
+ 
+ 	ctx = parser_callback_context_stack;
+ 	if(ctx != NULL)
+ 	{
+ 		ctx->action = action;
+ 		(*ctx->callback) (args);
+ 	}
+ }
+ 
+ /* this is a helper function to avoid some redundatcy for 
+  * function parameter refnames error messages
+  * 1 for parameter name not found.
+  */
+ void invalid_function_paramref_error(int errortype,ParseState *pstate, int plocation,char* name1,char* name2)
+ {
+ 	char *proname;
+ 
+ 	proname = get_func_name((Oid)parser_callback_context_stack->context_arg);
+ 	if(errortype == 1)
+ 	{
+ 			ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_FUNCTION_PARAMETER_NAME),
+ 				 errmsg("there is no parameter %s defined for function %s",
+ 						name1,proname),parser_errposition(pstate, plocation)));
+ 	}
+ 	else if(errortype == 2)
+ 	{
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_FUNCTION_PARAMETER_NAME),
+ 			errmsg("there is no parameter %s.%s defined for function %s or this \n is an invalid reference to FROM-clause entry for table \"%s\"",
+ 				   name1,name2,proname,name1),parser_errposition(pstate, plocation)));
+ 	}
+ }
+ 
+ /* Handler for parser callback. this function processes:
+  * 1. SQL-language parameters referenced by name
+  */
+ void 
+ sql_parser_callback_handler(void *args)
+ {
+ 	Oid	funcoid;
+ 	HeapTuple	tuple;
+ 	int	numargs;
+ 	int i;
+ 	int	numNodeNames;
+ 	Oid	*argtypes;
+ 	char **argnames;
+ 	char *argmodes;
+ 	char *name;
+ 	char *proname;
+ 	Node *node = NULL;
+ 	ParserCallbackColumnRefArgs *crefArgs;
+ 	ParserCallbackContext *currentctx = parser_callback_context_stack;
+ 
+ 	if(currentctx->context == T_ParsingFunctionBody)
+ 	{
+ 		funcoid = (Oid)currentctx->context_arg;
+ 		tuple = SearchSysCache(PROCOID,
+ 				ObjectIdGetDatum(funcoid),
+ 				0, 0, 0);
+ 
+ 		switch(currentctx->action)
+ 		{
+ 			case  A_ResolveAmbigColumnRef:
+ 				crefArgs = (ParserCallbackColumnRefArgs*)args;
+ 				crefArgs->result = NULL;
+ 				crefArgs->is_funcname_ambiguous = false;
+ 				crefArgs->is_invalid_parameter_name = false;
+ 
+ 				proname = get_func_name(funcoid);
+ 
+ 				numargs = get_func_arg_info(tuple,
+ 					&argtypes, &argnames, &argmodes);
+ 
+ 				/* numNodeNames contains the ColumnRef information that the
+ 				 * parser is trying to resolve.
+ 				 * either a single value or identifier.identifier */
+ 				numNodeNames = list_length(crefArgs->cref->fields);
+ 
+ 				/* validating this function's name from identifier.identifier */ 
+ 				if(numNodeNames == 2)
+ 				{
+ 					/* first field */ 
+ 					name = strVal(linitial(crefArgs->cref->fields));	
+ 
+ 					/* break if the first field is not equal to this function's name  */
+ 					if(strcmp(name,proname) != 0)
+ 					{
+ 						crefArgs->is_funcname_ambiguous = true;
+ 						break;
+ 					}
+ 					else
+ 					{
+ 						/* continue resolving with second item in cref*/
+ 						name = strVal(lsecond(crefArgs->cref->fields));
+ 					}
+ 				}
+ 				else
+ 				{
+ 					name = strVal(linitial(crefArgs->cref->fields));
+ 				}
+ 
+ 				for(i = 0; i < numargs; i++)
+ 				{
+ 					if(strcmp(argnames[i],name) == 0)
+ 					{
+ 						ParamRef pref;
+ 						pref.type = T_ParamRef;
+ 						pref.number = i+1;
+ 						node = transformExpr(crefArgs->pstate,(Node *)&pref);
+ 						crefArgs->result = node;
+ 						break;
+ 					}
+ 				}
+ 
+ 				if(node == NULL)
+ 					crefArgs->is_invalid_parameter_name = true;
+ 
+ 			break; /* A_ResolveAmbigColumnRef */
+ 		}
+ 
+ 		ReleaseSysCache(tuple);
+ 	}
+ }
*** pgsql/src/backend/parser/parse_expr.c.orig	2007-11-15 23:25:15.000000000 +0100
--- pgsql/src/backend/parser/parse_expr.c	2007-11-28 09:29:27.516369600 +0100
***************
*** 31,36 ****
--- 31,37 ----
  #include "parser/parse_relation.h"
  #include "parser/parse_target.h"
  #include "parser/parse_type.h"
+ #include "parser/parse_callback.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
  #include "utils/xml.h"
***************
*** 62,68 ****
  static Node *transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr);
  static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
  static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
! 					 char *relname, int location);
  static Node *transformIndirection(ParseState *pstate, Node *basenode,
  					 List *indirection);
  static Node *typecast_expression(ParseState *pstate, Node *expr,
--- 63,70 ----
  static Node *transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr);
  static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
  static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
! 					 char *relname, int location,
! 					 bool skip_error);
  static Node *transformIndirection(ParseState *pstate, Node *basenode,
  					 List *indirection);
  static Node *typecast_expression(ParseState *pstate, Node *expr,
***************
*** 354,362 ****
  	 * The allowed syntaxes are:
  	 *
  	 * A		First try to resolve as unqualified column name;
! 	 *			if no luck, try to resolve as unqualified table name (A.*).
  	 * A.B		A is an unqualified table name; B is either a
  	 *			column or function name (trying column name first).
  	 * A.B.C	schema A, table B, col or func name C.
  	 * A.B.C.D	catalog A, schema B, table C, col or func D.
  	 * A.*		A is an unqualified table name; means whole-row value.
--- 356,368 ----
  	 * The allowed syntaxes are:
  	 *
  	 * A		First try to resolve as unqualified column name;
! 	 *			if no luck, try to resolve as unqualified table name (A.*);
! 	 *          if no lock and when parsing a function try resolve as a
! 	 *          refference to argument name.
  	 * A.B		A is an unqualified table name; B is either a
  	 *			column or function name (trying column name first).
+ 	 *          or when parsing function A can be function name
+ 	 *          and B is a refference to parameter
  	 * A.B.C	schema A, table B, col or func name C.
  	 * A.B.C.D	catalog A, schema B, table C, col or func D.
  	 * A.*		A is an unqualified table name; means whole-row value.
***************
*** 410,423 ****
  					 */
  					if (refnameRangeTblEntry(pstate, NULL, name,
  											 &levels_up) != NULL)
  						node = transformWholeRowRef(pstate, NULL, name,
! 													cref->location);
  					else
  						ereport(ERROR,
  								(errcode(ERRCODE_UNDEFINED_COLUMN),
  								 errmsg("column \"%s\" does not exist",
  										name),
  								 parser_errposition(pstate, cref->location)));
  				}
  				break;
  			}
--- 416,454 ----
  					 */
  					if (refnameRangeTblEntry(pstate, NULL, name,
  											 &levels_up) != NULL)
+ 					{
  						node = transformWholeRowRef(pstate, NULL, name,
! 													cref->location,false);
! 					}
  					else
+ 					{
+ 						 /* if we are in context of parsing or a function
+ 						  * we make a final attempt to resolve this as column name ref */
+ 						if(parser_callback_context_stack != NULL &&
+ 								parser_callback_context_stack->context 
+ 								== T_ParsingFunctionBody)
+ 						{
+ 							ParserCallbackColumnRefArgs crefArgs;
+ 							crefArgs.pstate = pstate;
+ 							crefArgs.cref = cref;
+ 							parser_do_callback(A_ResolveAmbigColumnRef,&crefArgs);
+ 							node = crefArgs.result;
+ 
+ 							/* generate error if the parameter name is not found */
+ 							if(crefArgs.is_invalid_parameter_name)
+ 								invalid_function_paramref_error(1,pstate,cref->location,name,NULL);
+ 
+ 						}
+ 					}
+ 
+ 					if(node == NULL)
+ 					{
  						ereport(ERROR,
  								(errcode(ERRCODE_UNDEFINED_COLUMN),
  								 errmsg("column \"%s\" does not exist",
  										name),
  								 parser_errposition(pstate, cref->location)));
+ 					}
  				}
  				break;
  			}
***************
*** 425,442 ****
  			{
  				char	   *name1 = strVal(linitial(cref->fields));
  				char	   *name2 = strVal(lsecond(cref->fields));
  
  				/* Whole-row reference? */
  				if (strcmp(name2, "*") == 0)
  				{
  					node = transformWholeRowRef(pstate, NULL, name1,
! 												cref->location);
  					break;
  				}
  
  				/* Try to identify as a once-qualified column */
! 				node = qualifiedNameToVar(pstate, NULL, name1, name2, true,
! 										  cref->location);
  				if (node == NULL)
  				{
  					/*
--- 456,526 ----
  			{
  				char	   *name1 = strVal(linitial(cref->fields));
  				char	   *name2 = strVal(lsecond(cref->fields));
+ 				ParserCallbackColumnRefArgs crefArgs;
  
  				/* Whole-row reference? */
  				if (strcmp(name2, "*") == 0)
  				{
  					node = transformWholeRowRef(pstate, NULL, name1,
! 												cref->location,false);
  					break;
  				}
  
+ 				/* if we are in context of parsing a function */
+ 				if(parser_callback_context_stack != NULL &&
+ 					parser_callback_context_stack->context == T_ParsingFunctionBody)
+ 				{
+ 						node = qualifiedNameToVar(pstate, NULL, name1, name2, 
+ 							true,cref->location,true);
+ 
+ 						if(node == NULL)
+ 						{
+ 							/* we go for ParseFuncOrColumn */
+ 							node = transformWholeRowRef(pstate, NULL, name1,
+ 													cref->location,true);
+ 							
+ 							/* normally the method above with skip_error false 
+ 							 * would return a valid node (or stop with an error),
+ 							 * in this case when the node is null then there 
+ 							 * is not need to check it as FuncOrColumn */
+ 							if(node != NULL)
+ 							{
+ 								node = ParseFuncOrColumn(pstate,
+ 														 list_make1(makeString(name2)),
+ 														 list_make1(node),
+ 														 false, false, true,
+ 														 cref->location);
+ 								break;
+ 							}
+ 
+ 							/* reaching this point means refname (name1) does not exist
+ 							 * as table alias or any kind of RTE. So we do a final match
+ 							 * for function.parameter */
+ 							crefArgs.pstate = pstate;
+ 							crefArgs.cref = cref;
+ 							parser_do_callback(A_ResolveAmbigColumnRef,&crefArgs);
+ 							node = crefArgs.result;
+ 
+ 							/* generate error if the parameter name is not found */
+ 							if(crefArgs.is_invalid_parameter_name)
+ 								invalid_function_paramref_error(1,pstate,cref->location,name2,NULL);
+ 
+ 							/* at this point either relname is invalid of relname is not the 
+ 							 * name of this function */
+ 							if(crefArgs.is_funcname_ambiguous)
+ 								invalid_function_paramref_error(2,pstate,cref->location,name1,name2);						}
+ 						else
+ 						{
+ 							break;
+ 						}
+ 				}
+ 				else
+ 					node = NULL;
+ 
  				/* Try to identify as a once-qualified column */
! 				if(node == NULL)
! 					node = qualifiedNameToVar(pstate, NULL, name1, name2, true,
! 										  cref->location,false);
  				if (node == NULL)
  				{
  					/*
***************
*** 445,451 ****
  					 * implicit RTE for tables not already entered.
  					 */
  					node = transformWholeRowRef(pstate, NULL, name1,
! 												cref->location);
  					node = ParseFuncOrColumn(pstate,
  											 list_make1(makeString(name2)),
  											 list_make1(node),
--- 529,535 ----
  					 * implicit RTE for tables not already entered.
  					 */
  					node = transformWholeRowRef(pstate, NULL, name1,
! 												cref->location,false);
  					node = ParseFuncOrColumn(pstate,
  											 list_make1(makeString(name2)),
  											 list_make1(node),
***************
*** 464,481 ****
  				if (strcmp(name3, "*") == 0)
  				{
  					node = transformWholeRowRef(pstate, name1, name2,
! 												cref->location);
  					break;
  				}
  
  				/* Try to identify as a twice-qualified column */
  				node = qualifiedNameToVar(pstate, name1, name2, name3, true,
! 										  cref->location);
  				if (node == NULL)
  				{
  					/* Try it as a function call */
  					node = transformWholeRowRef(pstate, name1, name2,
! 												cref->location);
  					node = ParseFuncOrColumn(pstate,
  											 list_make1(makeString(name3)),
  											 list_make1(node),
--- 548,565 ----
  				if (strcmp(name3, "*") == 0)
  				{
  					node = transformWholeRowRef(pstate, name1, name2,
! 												cref->location,false);
  					break;
  				}
  
  				/* Try to identify as a twice-qualified column */
  				node = qualifiedNameToVar(pstate, name1, name2, name3, true,
! 										  cref->location,false);
  				if (node == NULL)
  				{
  					/* Try it as a function call */
  					node = transformWholeRowRef(pstate, name1, name2,
! 												cref->location,false);
  					node = ParseFuncOrColumn(pstate,
  											 list_make1(makeString(name3)),
  											 list_make1(node),
***************
*** 505,522 ****
  				if (strcmp(name4, "*") == 0)
  				{
  					node = transformWholeRowRef(pstate, name2, name3,
! 												cref->location);
  					break;
  				}
  
  				/* Try to identify as a twice-qualified column */
  				node = qualifiedNameToVar(pstate, name2, name3, name4, true,
! 										  cref->location);
  				if (node == NULL)
  				{
  					/* Try it as a function call */
  					node = transformWholeRowRef(pstate, name2, name3,
! 												cref->location);
  					node = ParseFuncOrColumn(pstate,
  											 list_make1(makeString(name4)),
  											 list_make1(node),
--- 589,606 ----
  				if (strcmp(name4, "*") == 0)
  				{
  					node = transformWholeRowRef(pstate, name2, name3,
! 												cref->location,false);
  					break;
  				}
  
  				/* Try to identify as a twice-qualified column */
  				node = qualifiedNameToVar(pstate, name2, name3, name4, true,
! 										  cref->location,false);
  				if (node == NULL)
  				{
  					/* Try it as a function call */
  					node = transformWholeRowRef(pstate, name2, name3,
! 												cref->location,false);
  					node = ParseFuncOrColumn(pstate,
  											 list_make1(makeString(name4)),
  											 list_make1(node),
***************
*** 1655,1667 ****
   */
  static Node *
  transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
! 					 int location)
  {
  	Node	   *result;
  	RangeTblEntry *rte;
  	int			vnum;
  	int			sublevels_up;
  	Oid			toid;
  
  	/* Look up the referenced RTE, creating it if needed */
  
--- 1739,1752 ----
   */
  static Node *
  transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
! 					 int location,bool skip_error)
  {
  	Node	   *result;
  	RangeTblEntry *rte;
  	int			vnum;
  	int			sublevels_up;
  	Oid			toid;
+ 	int skiped_sqlerrorcode;
  
  	/* Look up the referenced RTE, creating it if needed */
  
***************
*** 1670,1676 ****
  
  	if (rte == NULL)
  		rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
! 							 location);
  
  	vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
  
--- 1755,1764 ----
  
  	if (rte == NULL)
  		rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
! 							 location,skip_error,&skiped_sqlerrorcode);
! 
! 	if(!rte & skip_error && skiped_sqlerrorcode != 0)
! 		return NULL;
  
  	vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
  
*** pgsql/src/backend/parser/parse_relation.c.orig	2007-11-11 20:22:49.000000000 +0100
--- pgsql/src/backend/parser/parse_relation.c	2007-11-27 12:53:10.926588800 +0100
***************
*** 48,54 ****
  				List **colnames, List **colvars);
  static int	specialAttNum(const char *attname);
  static void warnAutoRange(ParseState *pstate, RangeVar *relation,
! 			  int location);
  
  
  /*
--- 48,54 ----
  				List **colnames, List **colvars);
  static int	specialAttNum(const char *attname);
  static void warnAutoRange(ParseState *pstate, RangeVar *relation,
! 			  int location,bool skip_error,int  *skiped_sqlerrorcode);
  
  
  /*
***************
*** 460,469 ****
  				   char *refname,
  				   char *colname,
  				   bool implicitRTEOK,
! 				   int location)
  {
  	RangeTblEntry *rte;
  	int			sublevels_up;
  
  	rte = refnameRangeTblEntry(pstate, schemaname, refname, &sublevels_up);
  
--- 460,471 ----
  				   char *refname,
  				   char *colname,
  				   bool implicitRTEOK,
! 				   int location,
! 				   bool skip_error)
  {
  	RangeTblEntry *rte;
  	int			sublevels_up;
+ 	int skiped_sqlerrorcode;
  
  	rte = refnameRangeTblEntry(pstate, schemaname, refname, &sublevels_up);
  
***************
*** 472,480 ****
  		if (!implicitRTEOK)
  			return NULL;
  		rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname),
! 							 location);
  	}
  
  	return scanRTEForColumn(pstate, rte, colname, location);
  }
  
--- 474,487 ----
  		if (!implicitRTEOK)
  			return NULL;
  		rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname),
! 							 location,
! 							 skip_error,
! 							 &skiped_sqlerrorcode);
  	}
  
+ 	if(!rte & skip_error && skiped_sqlerrorcode != 0)
+ 		return NULL;
+ 
  	return scanRTEForColumn(pstate, rte, colname, location);
  }
  
***************
*** 1139,1150 ****
   * a conflicting name.
   */
  RangeTblEntry *
! addImplicitRTE(ParseState *pstate, RangeVar *relation, int location)
  {
  	RangeTblEntry *rte;
  
  	/* issue warning or error as needed */
! 	warnAutoRange(pstate, relation, location);
  
  	/*
  	 * Note that we set inFromCl true, so that the RTE will be listed
--- 1146,1160 ----
   * a conflicting name.
   */
  RangeTblEntry *
! addImplicitRTE(ParseState *pstate, RangeVar *relation, int location,bool skip_error,int *skiped_sqlerrorcode)
  {
  	RangeTblEntry *rte;
  
  	/* issue warning or error as needed */
! 	warnAutoRange(pstate, relation, location,skip_error,skiped_sqlerrorcode);
! 
! 	if(skip_error && *skiped_sqlerrorcode != 0)
! 		return NULL;
  
  	/*
  	 * Note that we set inFromCl true, so that the RTE will be listed
***************
*** 1955,1966 ****
   * a warning.
   */
  static void
! warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
  {
  	RangeTblEntry *rte;
  	int			sublevels_up;
  	const char *badAlias = NULL;
  
  	/*
  	 * Check to see if there are any potential matches in the query's
  	 * rangetable.	This affects the message we provide.
--- 1965,1981 ----
   * a warning.
   */
  static void
! warnAutoRange(ParseState *pstate, RangeVar *relation, int location,
! 			  bool skip_error,int *skiped_sqlerrorcode)
  {
  	RangeTblEntry *rte;
  	int			sublevels_up;
  	const char *badAlias = NULL;
  
+ 	/* initializing if possible*/
+ 	if(skip_error)
+ 		*skiped_sqlerrorcode = 0;
+ 
  	/*
  	 * Check to see if there are any potential matches in the query's
  	 * rangetable.	This affects the message we provide.
***************
*** 1983,1988 ****
--- 1998,2009 ----
  							 &sublevels_up) == rte)
  		badAlias = rte->eref->aliasname;
  
+ 	if(!rte && skip_error)
+ 	{
+ 		*skiped_sqlerrorcode = ERRCODE_UNDEFINED_TABLE;
+ 		return;
+ 	}
+ 
  	if (!add_missing_from)
  	{
  		if (rte)
*** pgsql/src/backend/parser/parse_target.c.orig	2007-11-15 22:14:37.000000000 +0100
--- pgsql/src/backend/parser/parse_target.c	2007-11-26 11:23:36.400586800 +0100
***************
*** 890,896 ****
  								   &sublevels_up);
  		if (rte == NULL)
  			rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
! 								 cref->location);
  
  		/* Require read access --- see comments in setTargetTable() */
  		rte->requiredPerms |= ACL_SELECT;
--- 890,896 ----
  								   &sublevels_up);
  		if (rte == NULL)
  			rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
! 								 cref->location,false,NULL);
  
  		/* Require read access --- see comments in setTargetTable() */
  		rte->requiredPerms |= ACL_SELECT;
*** pgsql/src/backend/parser/Makefile.orig	2007-06-24 00:12:51.000000000 +0200
--- pgsql/src/backend/parser/Makefile	2007-11-26 11:23:36.430629400 +0100
***************
*** 14,20 ****
  
  OBJS= analyze.o gram.o keywords.o parser.o parse_agg.o parse_clause.o \
        parse_expr.o parse_func.o parse_node.o parse_oper.o parse_relation.o \
!       parse_type.o parse_coerce.o parse_target.o parse_utilcmd.o scansup.o
  
  FLEXFLAGS = -CF
  
--- 14,21 ----
  
  OBJS= analyze.o gram.o keywords.o parser.o parse_agg.o parse_clause.o \
        parse_expr.o parse_func.o parse_node.o parse_oper.o parse_relation.o \
!       parse_type.o parse_coerce.o parse_target.o parse_utilcmd.o scansup.o \
!       parse_callback.o
  
  FLEXFLAGS = -CF
  
*** pgsql/src/include/parser/parse_callback.h.orig	1970-01-01 01:00:00.000000000 +0100
--- pgsql/src/include/parser/parse_callback.h	2007-11-26 13:09:15.980024600 +0100
***************
*** 0 ****
--- 1,68 ----
+ /*-------------------------------------------------------------------------
+  *
+  * parse_callback.h
+  *	  Definitions for the parser callback mechanism 
+  *
+  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *	  $PostgreSQL: pgsql/src/backend/parser/parse_callback.h $
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ /* provides information to callback handler function to determine
+  * in wat context whis callback is called.
+  */
+ typedef enum ParserCallbackContextTag
+ {
+   T_ParsingFunctionBody = 1
+ } ParserCallbackContextTag;
+ 
+ /* Action types that is passed to the callback handler. */
+ typedef enum ParserCallbackActionTag
+ {
+ 	A_ResolveAmbigColumnRef = 1
+ } ParserCallbackActionTag;
+ 
+ /* Support for handling callbacks from within the parser to 
+  * external functions.
+  */
+ typedef struct ParserCallbackContext
+ {
+ 	/* provides information about the this callback context */
+ 	ParserCallbackContextTag context; 
+ 
+ 	/* What to do in callback handler function */
+ 	ParserCallbackActionTag action; 
+ 
+ 	/* previous callback context */
+ 	struct ParserCallbackContext *previous;  
+ 
+ 	/* handler to be called for in this context */
+ 	void (*callback) (void *callback_arguments); 
+ 
+ 	/* global argument set when a handler is setup */
+ 	void *context_arg;
+ } ParserCallbackContext;
+ 
+ /* Support for passing ColumnRef data from within parser 
+  * to callback handler function */
+ typedef struct ParserCallbackColumnRefArgs
+ {
+ 	ParseState *pstate;		/* parser state */
+ 	ColumnRef  *cref;		/* current ColumnRef that is being processed in parser */ 
+ 	Node	   *result;      /* the result of callback handler function */
+ 	bool       is_funcname_ambiguous; 
+ 	bool	   is_invalid_parameter_name;
+ } ParserCallbackColumnRefArgs;
+ 
+ /* global callback handler */
+ extern PGDLLIMPORT ParserCallbackContext *parser_callback_context_stack;
+ extern void parser_do_callback(ParserCallbackActionTag action, void *args);
+ extern void sql_parser_callback_handler(void *args);
+ extern void invalid_function_paramref_error(int error,ParseState *pstate, int plocation,
+ 									 char* name1,char* name2);
+ 
*** pgsql/src/include/parser/parse_relation.h.orig	2007-01-05 23:19:57.000000000 +0100
--- pgsql/src/include/parser/parse_relation.h	2007-11-27 12:47:41.452828800 +0100
***************
*** 39,45 ****
  				   char *refname,
  				   char *colname,
  				   bool implicitRTEOK,
! 				   int location);
  extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
  				   RangeVar *relation,
  				   Alias *alias,
--- 39,46 ----
  				   char *refname,
  				   char *colname,
  				   bool implicitRTEOK,
! 				   int location,
! 				   bool skip_error);
  extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
  				   RangeVar *relation,
  				   Alias *alias,
***************
*** 73,79 ****
  			  bool addToJoinList,
  			  bool addToRelNameSpace, bool addToVarNameSpace);
  extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation,
! 			   int location);
  extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
  		  bool include_dropped,
  		  List **colnames, List **colvars);
--- 74,82 ----
  			  bool addToJoinList,
  			  bool addToRelNameSpace, bool addToVarNameSpace);
  extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation,
! 			   int location,
! 			   bool skip_error,
! 			   int *skiped_sqlerrorcode);
  extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
  		  bool include_dropped,
  		  List **colnames, List **colvars);
*** pgsql/src/include/utils/errcodes.h.orig	2007-02-03 15:06:56.000000000 +0100
--- pgsql/src/include/utils/errcodes.h	2007-11-26 11:23:36.490714600 +0100
***************
*** 293,298 ****
--- 293,299 ----
  #define ERRCODE_INVALID_SCHEMA_DEFINITION	MAKE_SQLSTATE('4','2', 'P','1','5')
  #define ERRCODE_INVALID_TABLE_DEFINITION	MAKE_SQLSTATE('4','2', 'P','1','6')
  #define ERRCODE_INVALID_OBJECT_DEFINITION	MAKE_SQLSTATE('4','2', 'P','1','7')
+ #define ERRCODE_UNDEFINED_FUNCTION_PARAMETER_NAME	MAKE_SQLSTATE('4','2', 'P','1','8')
  
  /* Class 44 - WITH CHECK OPTION Violation */
  #define ERRCODE_WITH_CHECK_OPTION_VIOLATION MAKE_SQLSTATE('4','4', '0','0','0')
*** pgsql/src/test/regress/serial_schedule.orig	2007-11-24 21:41:35.000000000 +0100
--- pgsql/src/test/regress/serial_schedule	2007-11-26 11:23:36.520757200 +0100
***************
*** 115,117 ****
--- 115,118 ----
  test: xml
  test: stats
  test: tablespace
+ test: func_paramname_ref
*** pgsql/src/test/regress/parallel_schedule.orig	2007-11-24 20:49:23.000000000 +0100
--- pgsql/src/test/regress/parallel_schedule	2007-11-26 11:23:36.540785600 +0100
***************
*** 69,75 ****
  # ----------
  # Another group of parallel tests
  # ----------
! test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete
  
  test: privileges
  test: misc
--- 69,75 ----
  # ----------
  # Another group of parallel tests
  # ----------
! test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete func_paramname_ref
  
  test: privileges
  test: misc
*** pgsql/src/test/regress/expected/func_paramname_ref.out.orig	1970-01-01 01:00:00.000000000 +0100
--- pgsql/src/test/regress/expected/func_paramname_ref.out	2007-11-27 11:07:55.325200000 +0100
***************
*** 0 ****
--- 1,248 ----
+ CREATE TABLE tbl1(id serial,field1 integer,field2 varchar);
+ NOTICE:  CREATE TABLE will create implicit sequence "tbl1_id_seq" for serial column "tbl1.id"
+ INSERT INTO tbl1 (field1,field2) VALUES (1,'====');
+ INSERT INTO tbl1 (field1,field2) VALUES (2,'++++');
+ INSERT INTO tbl1 (field1,field2) VALUES (3,'))))');
+ INSERT INTO tbl1 (field1,field2) VALUES (4,'((((');
+ -- TEST GROUP 1
+ -- test single parameter
+ CREATE FUNCTION ftest1(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT param1 * 2;
+ $$
+ LANGUAGE SQL;
+ -- test func.param parameter with function name
+ CREATE FUNCTION ftest2(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT ftest2.param1 * 2; 
+ $$
+ LANGUAGE SQL;
+ -- test function in function parameter with function name
+ CREATE FUNCTION ftest3(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT ftest3.param1 + ftest2(2); 
+ $$
+ LANGUAGE SQL;
+ -- testing functions above
+ SELECT ftest1(2);
+  ftest1 
+ --------
+       4
+ (1 row)
+ 
+ SELECT ftest2(4);
+  ftest2 
+ --------
+       8
+ (1 row)
+ 
+ SELECT ftest3(2);
+  ftest3 
+ --------
+       6
+ (1 row)
+ 
+ -- TEST GROUP 2
+ CREATE FUNCTION ftest4(param1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT *,param1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ CREATE FUNCTION ftest5(param1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT *,param1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ CREATE FUNCTION ftest6(param1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT *,ftest6.param1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ CREATE FUNCTION ftest7(param1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT tbl1.field1 || ' ' || ftest7.param1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ CREATE FUNCTION ftest8(param1 integer,param2 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT 
+ 				a.field1,
+ 				ftest8.param1,
+ 				ftest8.param2,
+ 				param1,
+ 				param2
+ 		FROM 
+ 				tbl1 a 
+ 		WHERE 
+ 				a.field1 = ftest8.param1 OR
+ 			  	a.field2 = param2;
+ $$
+ LANGUAGE SQL;
+ CREATE FUNCTION ftest9(field1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT tbl1.field1 || ' ' || ftest9.field1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ -- should return tbl1 fields only
+ CREATE FUNCTION ftest10(field1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT tbl1.field1 || ' ' || field1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ CREATE FUNCTION ftest11(field1 integer,field2 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT 
+ 				a.field1,
+ 				a.field2,
+ 				b.field1,
+ 				b.field2,
+ 				ftest11.field1,
+ 				ftest11.field2,
+ 				c.*
+ 				
+ 		FROM 
+ 				tbl1 a 
+ 				INNER JOIN tbl1 b on a.field1 = b.field1
+ 				INNER JOIN (select ftest11.field1,field2) c on a.field1 = c.field1;
+ $$
+ LANGUAGE SQL;
+ -- testing functions above
+ SELECT ftest4('aaaa');
+       ftest4       
+ -------------------
+  (1,1,====,aaaa)
+  (2,2,++++,aaaa)
+  (3,3,"))))",aaaa)
+  (4,4,"((((",aaaa)
+ (4 rows)
+ 
+ SELECT ftest5('bbbb');
+       ftest5       
+ -------------------
+  (1,1,====,bbbb)
+  (2,2,++++,bbbb)
+  (3,3,"))))",bbbb)
+  (4,4,"((((",bbbb)
+ (4 rows)
+ 
+ SELECT ftest6('cccc');
+       ftest6       
+ -------------------
+  (1,1,====,cccc)
+  (2,2,++++,cccc)
+  (3,3,"))))",cccc)
+  (4,4,"((((",cccc)
+ (4 rows)
+ 
+ SELECT ftest7('dddd');
+    ftest7   
+ ------------
+  ("1 dddd")
+  ("2 dddd")
+  ("3 dddd")
+  ("4 dddd")
+ (4 rows)
+ 
+ SELECT ftest8(2,'((((');
+         ftest8         
+ -----------------------
+  (2,2,"((((",2,"((((")
+  (4,2,"((((",2,"((((")
+ (2 rows)
+ 
+ SELECT ftest9('foo');
+   ftest9   
+ -----------
+  ("1 foo")
+  ("2 foo")
+  ("3 foo")
+  ("4 foo")
+ (4 rows)
+ 
+ SELECT ftest10('foo');
+  ftest10 
+ ---------
+  ("1 1")
+  ("2 2")
+  ("3 3")
+  ("4 4")
+ (4 rows)
+ 
+ SELECT ftest11(2,'foo');
+            ftest11           
+ -----------------------------
+  (2,++++,2,++++,2,foo,2,foo)
+ (1 row)
+ 
+ -- TEST GROUP 3 (COMPUTED COLUMN)
+ CREATE TABLE empl (name text,salary numeric,age integer);
+ INSERT INTO empl(name,salary,age) VALUES ('A. Manager',100,55);
+ INSERT INTO empl(name,salary,age) VALUES ('B. Developer',300,30);
+ CREATE FUNCTION double_salary(employee empl) RETURNS numeric AS $$
+     SELECT (employee).salary * 2 AS salary; 
+ $$ LANGUAGE SQL; 
+ SELECT name, double_salary(empl.*) AS dream FROM empl;
+      name     | dream 
+ --------------+-------
+  A. Manager   |   200
+  B. Developer |   600
+ (2 rows)
+ 
+ -- ERRORS
+ CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT param2 * 2;
+ $$
+ LANGUAGE SQL;
+ ERROR:  there is no parameter param2 defined for function ftest_error
+ LINE 3:   SELECT param2 * 2;
+                  ^
+ CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT ftest_error.param2 * 2;
+ $$
+ LANGUAGE SQL;
+ ERROR:  there is no parameter param2 defined for function ftest_error
+ LINE 3:   SELECT ftest_error.param2 * 2;
+                  ^
+ CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT ftest_error_zz.param1 * 2;
+ $$
+ LANGUAGE SQL;
+ ERROR:  there is no parameter ftest_error_zz.param1 defined for function ftest_error or this 
+  is an invalid reference to FROM-clause entry for table "ftest_error_zz"
+ LINE 3:   SELECT ftest_error_zz.param1 * 2;
+                  ^
+ CREATE FUNCTION ftest_error(param1 integer,param2 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT 
+ 				a.field1,
+ 				ftest_error.param1,
+ 				ftest_error.param2 
+ 		FROM 
+ 				tbl1 a 
+ 		WHERE 
+ 				a.field1 = ftest_error_zz.param1 OR
+ 			  	a.field2 = param2;
+ $$
+ LANGUAGE SQL;
+ ERROR:  there is no parameter ftest_error_zz.param1 defined for function ftest_error or this 
+  is an invalid reference to FROM-clause entry for table "ftest_error_zz"
+ LINE 10:     a.field1 = ftest_error_zz.param1 OR
+                         ^
+ --- cleanup
+ DROP FUNCTION double_salary(empl);
+ DROP FUNCTION ftest11(integer,varchar);
+ DROP FUNCTION ftest10(varchar);
+ DROP FUNCTION ftest9(varchar);
+ DROP FUNCTION ftest8(integer,varchar);
+ DROP FUNCTION ftest7(varchar);
+ DROP FUNCTION ftest6(varchar);
+ DROP FUNCTION ftest5(varchar);
+ DROP FUNCTION ftest4(varchar);
+ DROP FUNCTION ftest3(integer);
+ DROP FUNCTION ftest2(integer);
+ DROP FUNCTION ftest1(integer);
+ DROP TABLE tbl1;
+ DROP TABLE empl;
\ No newline at end of file
*** pgsql/src/test/regress/sql/func_paramname_ref.sql.orig	1970-01-01 01:00:00.000000000 +0100
--- pgsql/src/test/regress/sql/func_paramname_ref.sql	2007-11-27 10:36:46.548030400 +0100
***************
*** 0 ****
--- 1,189 ----
+ CREATE TABLE tbl1(id serial,field1 integer,field2 varchar);
+ INSERT INTO tbl1 (field1,field2) VALUES (1,'====');
+ INSERT INTO tbl1 (field1,field2) VALUES (2,'++++');
+ INSERT INTO tbl1 (field1,field2) VALUES (3,'))))');
+ INSERT INTO tbl1 (field1,field2) VALUES (4,'((((');
+ 
+ 
+ 
+ -- TEST GROUP 1
+ -- test single parameter
+ CREATE FUNCTION ftest1(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT param1 * 2;
+ $$
+ LANGUAGE SQL;
+ 
+ -- test func.param parameter with function name
+ CREATE FUNCTION ftest2(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT ftest2.param1 * 2; 
+ $$
+ LANGUAGE SQL;
+ 
+ 
+ -- test function in function parameter with function name
+ CREATE FUNCTION ftest3(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT ftest3.param1 + ftest2(2); 
+ $$
+ LANGUAGE SQL;
+ 
+ -- testing functions above
+ 
+ SELECT ftest1(2);
+ SELECT ftest2(4);
+ SELECT ftest3(2);
+ 
+ 
+ -- TEST GROUP 2
+ 
+ CREATE FUNCTION ftest4(param1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT *,param1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ 
+ CREATE FUNCTION ftest5(param1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT *,param1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ 
+ 
+ CREATE FUNCTION ftest6(param1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT *,ftest6.param1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ 
+ CREATE FUNCTION ftest7(param1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT tbl1.field1 || ' ' || ftest7.param1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ 
+ CREATE FUNCTION ftest8(param1 integer,param2 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT 
+ 				a.field1,
+ 				ftest8.param1,
+ 				ftest8.param2,
+ 				param1,
+ 				param2
+ 		FROM 
+ 				tbl1 a 
+ 		WHERE 
+ 				a.field1 = ftest8.param1 OR
+ 			  	a.field2 = param2;
+ $$
+ LANGUAGE SQL;
+ 
+ 
+ CREATE FUNCTION ftest9(field1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT tbl1.field1 || ' ' || ftest9.field1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ 
+ -- should return tbl1 fields only
+ CREATE FUNCTION ftest10(field1 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT tbl1.field1 || ' ' || field1 FROM tbl1;
+ $$
+ LANGUAGE SQL;
+ 
+ 
+ CREATE FUNCTION ftest11(field1 integer,field2 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT 
+ 				a.field1,
+ 				a.field2,
+ 				b.field1,
+ 				b.field2,
+ 				ftest11.field1,
+ 				ftest11.field2,
+ 				c.*
+ 				
+ 		FROM 
+ 				tbl1 a 
+ 				INNER JOIN tbl1 b on a.field1 = b.field1
+ 				INNER JOIN (select ftest11.field1,field2) c on a.field1 = c.field1;
+ $$
+ LANGUAGE SQL;
+ 
+ -- testing functions above
+ 
+ SELECT ftest4('aaaa');
+ SELECT ftest5('bbbb');
+ SELECT ftest6('cccc');
+ SELECT ftest7('dddd');
+ SELECT ftest8(2,'((((');
+ SELECT ftest9('foo');
+ SELECT ftest10('foo');
+ SELECT ftest11(2,'foo');
+ 
+ 
+ -- TEST GROUP 3 (COMPUTED COLUMN)
+ 
+ CREATE TABLE empl (name text,salary numeric,age integer);
+ INSERT INTO empl(name,salary,age) VALUES ('A. Manager',100,55);
+ INSERT INTO empl(name,salary,age) VALUES ('B. Developer',300,30);
+ 
+ CREATE FUNCTION double_salary(employee empl) RETURNS numeric AS $$
+     SELECT (employee).salary * 2 AS salary; 
+ $$ LANGUAGE SQL; 
+ 
+ SELECT name, double_salary(empl.*) AS dream FROM empl;
+ 
+ -- ERRORS
+ 
+ CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT param2 * 2;
+ $$
+ LANGUAGE SQL;
+ 
+ CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT ftest_error.param2 * 2;
+ $$
+ LANGUAGE SQL;
+ 
+ CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS
+ $$
+ 		SELECT ftest_error_zz.param1 * 2;
+ $$
+ LANGUAGE SQL;
+ 
+ CREATE FUNCTION ftest_error(param1 integer,param2 varchar) RETURNS SETOF record AS
+ $$
+ 		SELECT 
+ 				a.field1,
+ 				ftest_error.param1,
+ 				ftest_error.param2 
+ 		FROM 
+ 				tbl1 a 
+ 		WHERE 
+ 				a.field1 = ftest_error_zz.param1 OR
+ 			  	a.field2 = param2;
+ $$
+ LANGUAGE SQL;
+ 
+ --- cleanup
+ DROP FUNCTION double_salary(empl);
+ DROP FUNCTION ftest11(integer,varchar);
+ DROP FUNCTION ftest10(varchar);
+ DROP FUNCTION ftest9(varchar);
+ DROP FUNCTION ftest8(integer,varchar);
+ DROP FUNCTION ftest7(varchar);
+ DROP FUNCTION ftest6(varchar);
+ DROP FUNCTION ftest5(varchar);
+ DROP FUNCTION ftest4(varchar);
+ DROP FUNCTION ftest3(integer);
+ DROP FUNCTION ftest2(integer);
+ DROP FUNCTION ftest1(integer);
+ 
+ 
+ DROP TABLE tbl1;
+ DROP TABLE empl;
