Hello All,
This patch implements a (generic) callback functionality in the parser.
The mechanism can be used to send callback messages from within the parser
to external functions.
I would like to know your opinion about the following:
In previous discussion Tom referred to:
>One point here is that it would be good to be able to qualify the argument
names with the function name, for example
> create function myfunc(x int) ...
> select ... from t where t.x = myfunc.x
The above is possible but I think qualifying the argument names with the
function name
can be cumbersome when one has to provide the function name multiple times.
For example: (where clause)
create or replace function sp_item_get_by_type_or_category(p_type
integer,p_category integer)
returns setof item_view as
$$
select ..... from item_view i
inner join tblcategory c on i.catid = c.catid
inner join tbltype t on i.typeid = t.typeid
where
c.catid = sp_item_get_by_type_or_category.p_category or
t.typeid = sp_item_get_by_type_or_categor.p_type;
$$
language sql;
Perhaps we could use the word "this" instead of the entire function name
For example:
....
where
c.catid = this.p_category or
t.typeid = this.p_type;
....
Any thoughts?
Regards,
Gevik
************************************************************************
PLEASE NOTE:
- This patch in created with MSVC++
- Resolving the argnames is not yet implemented correctly
due above.
- Two files have been added parse_callback.h and .c
How does it work:
>>> To setup callback;
ParserCallbackContext sqlcallbackcontext;
/* attaching parser callback handler*/
sqlcallbackcontext.context = T_ParsingFunctionBody;
sqlcallbackcontext.ctxarg = tuple;
sqlcallbackcontext.callback = sql_parser_callback_handler;
sqlcallbackcontext.previous = parser_callback_context_stack;
parser_callback_context_stack = &sqlcallbackcontext;
....
....
parser_callback_context_stack = sqlcallbackcontext.previous;
>>> To call the callback handler from within the parser:
ParserCallbackContextArgs args;
args.pstate = pstate;
args.input = (Node *)cref;
args.action = A_ResolveAmbigColumnRef;
parser_do_callback(&args);
To handle the callback:
if(context == T_ParsingFunctionBody)
{
switch(action)
{
case A_ResolveAmbigColumnRef:
....
}
}
*** I:\pgdev\pgsql\src\backend\catalog\pg_proc.c.orig 2007-09-03
02:39:14.000000000 +0200
--- I:\pgdev\pgsql\src\backend\catalog\pg_proc.c 2007-11-03
12:29:13.832352000 +0100
***************
*** 33,45 ****
#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);
Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
static void sql_function_parse_error_callback(void *arg);
static int match_prosrc_to_query(const char *prosrc, const char *queryText,
int cursorpos);
static bool match_prosrc_to_literal(const char *prosrc, const char *literal,
--- 33,47 ----
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
! #include "parser/parse_callback.h"
! #include "parser/parse_expr.h"
Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
Datum fmgr_c_validator(PG_FUNCTION_ARGS);
Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
static void sql_function_parse_error_callback(void *arg);
+ static void sql_parser_callback_handler(ParserCallbackContextArgs *args);
static int match_prosrc_to_query(const char *prosrc, const char *queryText,
int cursorpos);
static bool match_prosrc_to_literal(const char *prosrc, const char *literal,
***************
*** 531,536 ****
--- 533,539 ----
Datum tmp;
char *prosrc;
ErrorContextCallback sqlerrcontext;
+ ParserCallbackContext sqlcallbackcontext;
bool haspolyarg;
int i;
***************
*** 586,591 ****
--- 589,601 ----
sqlerrcontext.previous = error_context_stack;
error_context_stack = &sqlerrcontext;
+ /* attaching parser callback handler*/
+ sqlcallbackcontext.context = T_ParsingFunctionBody;
+ sqlcallbackcontext.ctxarg = tuple;
+ 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
***************
*** 607,612 ****
--- 617,623 ----
querytree_list = pg_parse_query(prosrc);
error_context_stack = sqlerrcontext.previous;
+ parser_callback_context_stack = sqlcallbackcontext.previous;
}
ReleaseSysCache(tuple);
***************
*** 614,619 ****
--- 625,660 ----
PG_RETURN_VOID();
}
+ /* handler for parser callback. this function is used to handle
+ * 1. SQL-language reference parameters by name
+ */
+ static void
+ sql_parser_callback_handler(ParserCallbackContextArgs *args)
+ {
+ HeapTuple tuple;
+ int numargs;
+ Oid *argtypes;
+ char **argnames;
+ char *argmodes;
+
+ ParserCallbackContext *currentctx = parser_callback_context_stack;
+ if(currentctx->context == T_ParsingFunctionBody)
+ {
+ switch(args->action)
+ {
+ case A_ResolveAmbigColumnRef:
+ tuple = (HeapTuple)currentctx->ctxarg;
+ numargs = get_func_arg_info(tuple,
+ &argtypes, &argnames, &argmodes);
+ /* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ * @ TODO:
+ * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ */
+ break;
+ }
+ }
+ }
+
/*
* Error context callback for handling errors in SQL function definitions
*/
*** I:\pgdev\pgsql\src\backend\parser\parse_callback.c.orig 1970-01-01
01:00:00.000000000 +0100
--- I:\pgdev\pgsql\src\backend\parser\parse_callback.c 2007-11-03
12:31:36.948142400 +0100
***************
*** 0 ****
--- 1,34 ----
+ /*-------------------------------------------------------------------------
+ *
+ * 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"
+
+ /* global parser callback handler context stack */
+ ParserCallbackContext *parser_callback_context_stack = NULL;
+
+ /* This function can be called from various positions within
+ * the parser to handle custom/language-specific actions.
+ * For example: The handling of referenced function argument names.
+ */
+ void parser_do_callback(ParserCallbackContextArgs *args)
+ {
+ ParserCallbackContext *ctx;
+ for (ctx = parser_callback_context_stack;
+ ctx != NULL;
+ ctx = ctx->previous)
+ (*ctx->callback) (args);
+ }
\ No newline at end of file
*** I:\pgdev\pgsql\src\backend\parser\parse_expr.c.orig 2007-06-24
00:12:51.000000000 +0200
--- I:\pgdev\pgsql\src\backend\parser\parse_expr.c 2007-11-03
11:42:27.737385600 +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"
***************
*** 410,423 ****
--- 411,442 ----
*/
if (refnameRangeTblEntry(pstate, NULL,
name,
&levels_up) != NULL)
+ {
node =
transformWholeRowRef(pstate, NULL, name,
cref->location);
+ }
else
+ {
+ /*
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ * @ TODO:
+ *
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ */
+ /* we make a final attempt to
resolve this column ref */
+ ParserCallbackContextArgs args;
+ args.pstate = pstate;
+ args.input = (Node *)cref;
+ args.action =
A_ResolveAmbigColumnRef;
+ parser_do_callback(&args);
+ }
+
+ if(node == NULL)
+ {
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column
\"%s\" does not exist",
name),
parser_errposition(pstate, cref->location)));
+ }
}
break;
}
*** I:\pgdev\pgsql\src\include\parser\parse_callback.h.orig 1970-01-01
01:00:00.000000000 +0100
--- I:\pgdev\pgsql\src\include\parser\parse_callback.h 2007-11-03
12:31:07.405662400 +0100
***************
*** 0 ****
--- 1,55 ----
+ /*-------------------------------------------------------------------------
+ *
+ * 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.
+ * PS: this list can be extended as needed.
+ */
+ typedef enum ParserCallbackContextTag
+ {
+ T_ParsingFunctionBody = 10
+ } ParserCallbackContextTag;
+
+ /* Action types that is passed to the callback handler.
+ * PS: this list can be extended as needed.
+ */
+ typedef enum ParserCallbackAction
+ {
+ A_ResolveAmbigColumnRef = 10
+ } ParserCallbackAction;
+
+ /* Support for handling callbacks from within the parser to
+ * external functions.
+ */
+ typedef struct ParserCallbackContext
+ {
+ ParserCallbackContextTag context; /* indicates the current context */
+ struct ParserCallbackContext *previous; /* previous callback context */
+ void (*callback) (ParserCallbackContextArgs); /* callback handler
function */
+ void *ctxarg; /* context argument set when a handler is setup */
+ } ParserCallbackContext;
+
+ /* Support for passing data from within parser to callback handler function */
+ typedef struct ParserCallbackContextArgs
+ {
+ ParseState *pstate; /* parser state */
+ Node *input; /* current Node that is being processed
in parser */
+ Node *result; /* the result of callback handler function */
+ ParserCallbackAction action; /* What to do in callback handler function
*/
+ } ParserCallbackContextArgs;
+
+ /* global callback handler */
+ extern PGDLLIMPORT ParserCallbackContext *parser_callback_context_stack;
+ extern void parser_do_callback(ParserCallbackContextArgs *args);
---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?
http://archives.postgresql.org