Select parser at runtime - Mailing list pgsql-hackers

From Ian Lance Taylor
Subject Select parser at runtime
Date
Msg-id siu1zf4d9h.fsf@daffy.airs.com
Whole thread Raw
Responses Re: Select parser at runtime
Re: [PATCHES] Select parser at runtime
List pgsql-hackers
I've been experimenting with using a different parser (one which is
more Oracle compatible).  While the parser is not yet ready for prime
time, I thought I would send out the code used to select the parser to
gauge its level of acceptability.  If this patch isn't going to fly,
then my approach to an alternate parser isn't going to fly either.

After this patch is applied, you can switch to a new parser by doing
something like this:

create function my_parser(opaque, opaque, opaque) returns opaque
  as '..../parser.so' language 'c';
set parser = my_parser;

After you do this, all subsequent input will be interpreted using the
specified parser.  Note that you may want to leave yourself an escape
hatch of some sort to set the parser back to Postgres standard.

If this patch is accepted, then some further work needs to be done to
set the parser for SPI calls, so that it is possible for the user to
change the parser while still using ordinary PL/pgSQL.

I would appreciate any feedback.

Ian

Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.230
diff -u -r1.230 postgres.c
--- src/backend/tcop/postgres.c    2001/08/04 00:14:43    1.230
+++ src/backend/tcop/postgres.c    2001/08/11 00:53:08
@@ -58,9 +58,11 @@
 #include "tcop/utility.h"
 #include "storage/proc.h"
 #include "utils/exc.h"
+#include "utils/fcache.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
+#include "utils/syscache.h"
 #ifdef MULTIBYTE
 #include "mb/pg_wchar.h"
 #endif
@@ -118,6 +120,10 @@
 */
 int            XfuncMode = 0;

+char *parser_function_name = 0;
+static bool update_parser_function_fcache = true;
+static FunctionCachePtr parser_function_fcache = NULL;
+
 /* ----------------------------------------------------------------
  *        decls for routines only used in this file
  * ----------------------------------------------------------------
@@ -389,8 +395,23 @@

     if (Show_parser_stats)
         ResetUsage();
+
+    if (update_parser_function_fcache)
+        assign_parser(parser_function_name);
+
+    if (parser_function_fcache == NULL)
+        raw_parsetree_list = parser(query_string, typev, nargs);
+    else
+    {
+        Datum    result;
+
+        parser_function_fcache->fcinfo.arg[0] = PointerGetDatum(query_string);
+        parser_function_fcache->fcinfo.arg[1] = PointerGetDatum(typev);
+        parser_function_fcache->fcinfo.arg[2] = Int32GetDatum(nargs);

-    raw_parsetree_list = parser(query_string, typev, nargs);
+        result = FunctionCallInvoke(&parser_function_fcache->fcinfo);
+        raw_parsetree_list = (List *) DatumGetPointer(result);
+    }

     if (Show_parser_stats)
     {
@@ -399,6 +420,82 @@
     }

     return raw_parsetree_list;
+}
+
+/*
+ * Check that we can find a parser function.  This is called when the
+ * user assigns a value to the `parser' variable.
+ */
+bool
+check_parser(const char *proposed)
+{
+    HeapTuple    tup;
+    Oid            argtypes[FUNC_MAX_ARGS];
+
+    if (proposed[0] == '\0' || strcmp(proposed, "postgres") == 0)
+        return true;
+
+    /* We can't check this unless we have started running.  */
+    if (! IsNormalProcessingMode())
+        return true;
+
+    memset(argtypes, 0, sizeof argtypes);
+    tup = SearchSysCache(PROCNAME,
+                         PointerGetDatum(proposed),
+                         Int32GetDatum(3),
+                         PointerGetDatum(argtypes),
+                         0);
+    if (! HeapTupleIsValid(tup))
+        return false;
+    ReleaseSysCache(tup);
+    return true;
+}
+
+/*
+ * Assign a new parser function.
+ */
+void
+assign_parser(const char *value)
+{
+    FunctionCachePtr    fcache;
+    HeapTuple            tup;
+    Oid                    argtypes[FUNC_MAX_ARGS];
+    Oid                    oid;
+
+    /* We can't update parser_function_fcache until we have started
+     * running.
+     */
+    if (! IsNormalProcessingMode())
+    {
+        update_parser_function_fcache = true;
+        return;
+    }
+
+    if (value[0] == '\0' || strcmp(value, "postgres") == 0)
+        fcache = NULL;
+    else
+    {
+        memset(argtypes, 0, sizeof argtypes);
+        tup = SearchSysCache(PROCNAME,
+                             PointerGetDatum(value),
+                             Int32GetDatum(3),
+                             PointerGetDatum(argtypes),
+                             0);
+        if (! HeapTupleIsValid(tup))
+            elog(ERROR, "parser function %s does not exist", value);
+
+        oid = tup->t_data->t_oid;
+
+        ReleaseSysCache(tup);
+
+        fcache = init_fcache(oid, 3, TopMemoryContext);
+    }
+
+    if (parser_function_fcache != NULL)
+        pfree(parser_function_fcache);
+    parser_function_fcache = fcache;
+
+    update_parser_function_fcache = false;
 }

 /*
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.45
diff -u -r1.45 guc.c
--- src/backend/utils/misc/guc.c    2001/07/05 15:19:40    1.45
+++ src/backend/utils/misc/guc.c    2001/08/11 00:53:11
@@ -376,6 +376,9 @@
     {"krb_server_keyfile", PGC_POSTMASTER, &pg_krb_server_keyfile,
     PG_KRB_SRVTAB, NULL, NULL},

+    {"parser", PGC_USERSET, &parser_function_name, "",
+     check_parser, assign_parser},
+
 #ifdef ENABLE_SYSLOG
     {"syslog_facility", PGC_POSTMASTER, &Syslog_facility,
     "LOCAL0", check_facility, NULL},
Index: src/include/tcop/tcopprot.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/tcop/tcopprot.h,v
retrieving revision 1.41
diff -u -r1.41 tcopprot.h
--- src/include/tcop/tcopprot.h    2001/06/08 21:16:48    1.41
+++ src/include/tcop/tcopprot.h    2001/08/11 00:53:12
@@ -31,6 +31,8 @@
 extern bool HostnameLookup;
 extern bool ShowPortNumber;

+extern char *parser_function_name;
+
 #ifndef BOOTSTRAP_INCLUDE

 extern List *pg_parse_and_rewrite(char *query_string,
@@ -39,6 +41,8 @@
 extern void pg_exec_query_string(char *query_string,
                      CommandDest dest,
                      MemoryContext parse_context);
+extern bool check_parser(const char *proposed);
+extern void assign_parser(const char *value);

 #endif     /* BOOTSTRAP_INCLUDE */


pgsql-hackers by date:

Previous
From: Tatsuo Ishii
Date:
Subject: Re: PL/pgSQL bug?
Next
From: "P. Dwayne Miller"
Date:
Subject: Re: Bug?