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: