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

Reply via email to