From ee8a721a838fc84ff6b8c29a73513f18c4bd027a Mon Sep 17 00:00:00 2001 From: xiaoby Date: Fri, 22 Jul 2022 09:51:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3SPI=E5=8F=97=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E8=A7=A3=E6=9E=90=E5=99=A8=E5=BD=B1=E5=93=8D?= =?UTF-8?q?=E8=80=8C=E5=AF=BC=E8=87=B4PL/pgSQL=E5=9C=A8=E5=90=AF=E7=94=A8?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E8=A7=A3=E6=9E=90=E5=99=A8=E6=97=B6?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E5=AF=BC=E8=87=B4=E9=9D=9E=E9=80=BE=E6=9C=9F?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SPI接口以及pg_parse_query函数添加一个默认参数可使用户指定不同的语法解析函数, 而不是直接调用raw_parser函数是要为以后新增加其它PL准备。 比如新增加兼容MySQL或其它存储过程时,它需要使用自已的语法解析, 又因为相同的语句在不同的数据库下可能存在不同的语义, 所以不可能做到完全兼容PG的语法(即便可以,工作量也会非常大)。 --- src/gausskernel/process/tcop/postgres.cpp | 17 ++++--- src/gausskernel/runtime/executor/spi.cpp | 55 ++++++++++++----------- src/include/executor/spi.h | 29 ++++++------ src/include/tcop/tcopprot.h | 3 +- 4 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/gausskernel/process/tcop/postgres.cpp b/src/gausskernel/process/tcop/postgres.cpp index a597b291f..626863e39 100755 --- a/src/gausskernel/process/tcop/postgres.cpp +++ b/src/gausskernel/process/tcop/postgres.cpp @@ -873,7 +873,8 @@ void LoadDolphinIfNeeded() * we've seen a COMMIT or ABORT command; when we are in abort state, other * commands are not processed any further than the raw parse stage. */ -List* pg_parse_query(const char* query_string, List** query_string_locationlist) +List* pg_parse_query(const char* query_string, List** query_string_locationlist, + List* (*parser_hook)(const char*, List**)) { List* raw_parsetree_list = NULL; PGSTAT_INIT_TIME_RECORD(); @@ -885,15 +886,17 @@ List* pg_parse_query(const char* query_string, List** query_string_locationlist) PGSTAT_START_TIME_RECORD(); - List* (*parser_hook)(const char*, List**) = raw_parser; + if (parser_hook == NULL) { + parser_hook = raw_parser; #ifndef ENABLE_MULTIPLE_NODES - if (u_sess->attr.attr_sql.whale || u_sess->attr.attr_sql.dolphin) { - int id = GetCustomParserId(); - if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) { - parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id]; + if (u_sess->attr.attr_sql.whale || u_sess->attr.attr_sql.dolphin) { + int id = GetCustomParserId(); + if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) { + parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id]; + } } - } #endif + } raw_parsetree_list = parser_hook(query_string, query_string_locationlist); PGSTAT_END_TIME_RECORD(PARSE_TIME); diff --git a/src/gausskernel/runtime/executor/spi.cpp b/src/gausskernel/runtime/executor/spi.cpp index d1cb3ebea..450e84627 100644 --- a/src/gausskernel/runtime/executor/spi.cpp +++ b/src/gausskernel/runtime/executor/spi.cpp @@ -58,7 +58,7 @@ static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, ParamL void _SPI_prepare_plan(const char *src, SPIPlanPtr plan); #ifdef PGXC -static void _SPI_pgxc_prepare_plan(const char *src, List *src_parsetree, SPIPlanPtr plan); +static void _SPI_pgxc_prepare_plan(const char *src, List *src_parsetree, SPIPlanPtr plan, parse_query_func parser); #endif void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan); @@ -734,7 +734,7 @@ void SPI_restore_connection(void) * bypass the parse stage. This is achieved here by calling * _SPI_pgxc_prepare_plan which accepts a parse tree. */ -int SPI_execute_direct(const char *remote_sql, char *nodename) +int SPI_execute_direct(const char *remote_sql, char *nodename, parse_query_func parser) { _SPI_plan plan; ExecDirectStmt *stmt = makeNode(ExecDirectStmt); @@ -761,7 +761,7 @@ int SPI_execute_direct(const char *remote_sql, char *nodename) plan.spi_key = INVALID_SPI_KEY; /* Now pass the ExecDirectStmt parsetree node */ - _SPI_pgxc_prepare_plan(execdirect.data, list_make1(stmt), &plan); + _SPI_pgxc_prepare_plan(execdirect.data, list_make1(stmt), &plan, parser); res = _SPI_execute_plan(&plan, NULL, InvalidSnapshot, InvalidSnapshot, false, true, 0, true); @@ -775,7 +775,7 @@ int SPI_execute_direct(const char *remote_sql, char *nodename) * Parse, plan, and execute a query string * @isCollectParam: default false, is used to collect sql info in sqladvisor online mode. */ -int SPI_execute(const char *src, bool read_only, long tcount, bool isCollectParam) +int SPI_execute(const char *src, bool read_only, long tcount, bool isCollectParam, parse_query_func parser) { _SPI_plan plan; @@ -794,7 +794,7 @@ int SPI_execute(const char *src, bool read_only, long tcount, bool isCollectPara plan.cursor_options = 0; plan.spi_key = INVALID_SPI_KEY; - _SPI_prepare_oneshot_plan(src, &plan); + _SPI_prepare_oneshot_plan(src, &plan, parser); res = _SPI_execute_plan(&plan, NULL, InvalidSnapshot, InvalidSnapshot, read_only, true, tcount); @@ -810,9 +810,9 @@ int SPI_execute(const char *src, bool read_only, long tcount, bool isCollectPara } /* Obsolete version of SPI_execute */ -int SPI_exec(const char *src, long tcount) +int SPI_exec(const char *src, long tcount, parse_query_func parser) { - return SPI_execute(src, false, tcount); + return SPI_execute(src, false, tcount, false, parser); } /* Execute a previously prepared plan */ @@ -907,7 +907,7 @@ int SPI_execute_snapshot(SPIPlanPtr plan, Datum *Values, const char *Nulls, Snap * SPI_execute_plan. */ int SPI_execute_with_args(const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, - long tcount, Cursor_Data *cursor_data) + long tcount, Cursor_Data *cursor_data, parse_query_func parser) { _SPI_plan plan; @@ -935,7 +935,7 @@ int SPI_execute_with_args(const char *src, int nargs, Oid *argtypes, Datum *Valu ParamListInfo param_list_info = _SPI_convert_params(nargs, argtypes, Values, Nulls, cursor_data); - _SPI_prepare_oneshot_plan(src, &plan); + _SPI_prepare_oneshot_plan(src, &plan, parser); res = _SPI_execute_plan(&plan, param_list_info, InvalidSnapshot, InvalidSnapshot, read_only, true, tcount); #ifdef ENABLE_MULTIPLE_NODES @@ -948,12 +948,12 @@ int SPI_execute_with_args(const char *src, int nargs, Oid *argtypes, Datum *Valu return res; } -SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes) +SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes, parse_query_func parser) { - return SPI_prepare_cursor(src, nargs, argtypes, 0); + return SPI_prepare_cursor(src, nargs, argtypes, 0, parser); } -SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, int cursorOptions) +SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, int cursorOptions, parse_query_func parser) { _SPI_plan plan; @@ -984,7 +984,7 @@ SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, int cur u_sess->SPI_cxt._current->spi_hash_key = INVALID_SPI_KEY; PG_TRY(); { - _SPI_prepare_plan(src, &plan); + _SPI_prepare_plan(src, &plan, parser); } PG_CATCH(); { @@ -1003,7 +1003,8 @@ SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, int cur return result; } -SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, int cursorOptions) +SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, int cursorOptions, + parse_query_func parser) { _SPI_plan plan; @@ -1030,7 +1031,7 @@ SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void plan.spi_key = INVALID_SPI_KEY; plan.id = (uint32)-1; - _SPI_prepare_plan(src, &plan); + _SPI_prepare_plan(src, &plan, parser); /* copy plan to procedure context */ SPIPlanPtr result = _SPI_make_plan_non_temp(&plan); @@ -1497,7 +1498,7 @@ Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const c * Parse and plan a query and open it as a portal. */ Portal SPI_cursor_open_with_args(const char *name, const char *src, int nargs, Oid *argtypes, Datum *Values, - const char *Nulls, bool read_only, int cursorOptions) + const char *Nulls, bool read_only, int cursorOptions, parse_query_func parser) { _SPI_plan plan; errno_t errorno = EOK; @@ -1542,7 +1543,7 @@ Portal SPI_cursor_open_with_args(const char *name, const char *src, int nargs, O u_sess->SPI_cxt._current->spi_hash_key = INVALID_SPI_KEY; PG_TRY(); { - _SPI_prepare_plan(src, &plan); + _SPI_prepare_plan(src, &plan, parser); } PG_CATCH(); { @@ -2208,10 +2209,10 @@ void spi_printtup(TupleTableSlot *slot, DestReceiver *self) * what we are creating is a "temporary" SPIPlan. Cruft generated during * parsing is also left in CurrentMemoryContext. */ -void _SPI_prepare_plan(const char *src, SPIPlanPtr plan) +void _SPI_prepare_plan(const char *src, SPIPlanPtr plan, parse_query_func parser) { #ifdef PGXC - _SPI_pgxc_prepare_plan(src, NULL, plan); + _SPI_pgxc_prepare_plan(src, NULL, plan, parser); } /* @@ -2220,7 +2221,7 @@ void _SPI_prepare_plan(const char *src, SPIPlanPtr plan) * called for internally executed execute-direct statements that are * transparent to the user. */ -static void _SPI_pgxc_prepare_plan(const char *src, List *src_parsetree, SPIPlanPtr plan) +static void _SPI_pgxc_prepare_plan(const char *src, List *src_parsetree, SPIPlanPtr plan, parse_query_func parser) { #endif List *raw_parsetree_list = NIL; @@ -2245,7 +2246,7 @@ static void _SPI_pgxc_prepare_plan(const char *src, List *src_parsetree, SPIPlan raw_parsetree_list = src_parsetree; else #endif - raw_parsetree_list = pg_parse_query(src); + raw_parsetree_list = pg_parse_query(src, NULL, parser); /* * Do parse analysis and rule rewrite for each raw parsetree, storing the * results into unsaved plancache entries. @@ -2398,7 +2399,7 @@ static void SPIParseOneShotPlan(CachedPlanSource* plansource, SPIPlanPtr plan) * what we are creating is a "temporary" SPIPlan. Cruft generated during * parsing is also left in CurrentMemoryContext. */ -void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan) +void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan, parse_query_func parser) { List *raw_parsetree_list = NIL; List *plancache_list = NIL; @@ -2417,7 +2418,7 @@ void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan) /* * Parse the request string into a list of raw parse trees. */ - raw_parsetree_list = pg_parse_query(src, &query_string_locationlist); + raw_parsetree_list = pg_parse_query(src, &query_string_locationlist, parser); /* * Construct plancache entries, but don't do parse analysis yet. @@ -3690,7 +3691,7 @@ DestReceiver *createAnalyzeSPIDestReceiver(CommandDest dest) * Returns: void */ void spi_exec_with_callback(CommandDest dest, const char *src, bool read_only, long tcount, bool direct_call, - void (*callbackFn)(void *), void *clientData) + void (*callbackFn)(void *), void *clientData, parse_query_func parser) { bool connected = false; int ret = 0; @@ -3707,7 +3708,7 @@ void spi_exec_with_callback(CommandDest dest, const char *src, bool read_only, l elog(DEBUG1, "Executing SQL: %s", src); /* Do the query. */ - ret = SPI_execute(src, read_only, tcount); + ret = SPI_execute(src, read_only, tcount, false, parser); Assert(ret > 0); if (direct_call && callbackFn != NULL) { @@ -3770,9 +3771,9 @@ List* _SPI_get_querylist(SPIPlanPtr plan) return plan ? plan->stmt_list : NULL; } -void _SPI_prepare_oneshot_plan_for_validator(const char *src, SPIPlanPtr plan) +void _SPI_prepare_oneshot_plan_for_validator(const char *src, SPIPlanPtr plan, parse_query_func parser) { - _SPI_prepare_oneshot_plan(src, plan); + _SPI_prepare_oneshot_plan(src, plan, parser); } void InitSPIPlanCxt() diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index a55ee877a..c27bfde30 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -66,6 +66,10 @@ typedef struct SPICachedPlanStack { #define SPI_OK_MERGE 15 #define SPI_OPT_NONATOMIC (1 << 0) +typedef List* (*parse_query_func)(const char *query_string, List **query_string_locationlist); +/* in postgres.cpp, avoid include tcopprot.h */ +extern List* raw_parser(const char* query_string, List** query_string_locationlist); + extern THR_LOCAL PGDLLIMPORT uint32 SPI_processed; extern THR_LOCAL PGDLLIMPORT SPITupleTable* SPI_tuptable; extern THR_LOCAL PGDLLIMPORT int SPI_result; @@ -79,19 +83,18 @@ extern void SPI_pop(void); extern bool SPI_push_conditional(void); extern void SPI_pop_conditional(bool pushed); extern void SPI_restore_connection(void); -extern int SPI_execute(const char* src, bool read_only, long tcount, bool isCollectParam = false); +extern int SPI_execute(const char* src, bool read_only, long tcount, bool isCollectParam = false, parse_query_func parser = raw_parser); extern int SPI_execute_plan(SPIPlanPtr plan, Datum* Values, const char* Nulls, bool read_only, long tcount); extern int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount); -extern int SPI_exec(const char* src, long tcount); +extern int SPI_exec(const char* src, long tcount, parse_query_func parser = raw_parser); extern int SPI_execp(SPIPlanPtr plan, Datum* Values, const char* Nulls, long tcount); extern int SPI_execute_snapshot(SPIPlanPtr plan, Datum* Values, const char* Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, long tcount); extern int SPI_execute_with_args(const char* src, int nargs, Oid* argtypes, Datum* Values, const char* Nulls, - bool read_only, long tcount, Cursor_Data* cursor_data); -extern SPIPlanPtr SPI_prepare(const char* src, int nargs, Oid* argtypes); -extern SPIPlanPtr SPI_prepare_cursor(const char* src, int nargs, Oid* argtypes, int cursorOptions); -extern SPIPlanPtr SPI_prepare_params( - const char* src, ParserSetupHook parserSetup, void* parserSetupArg, int cursorOptions); + bool read_only, long tcount, Cursor_Data* cursor_data, parse_query_func parser = raw_parser); +extern SPIPlanPtr SPI_prepare(const char* src, int nargs, Oid* argtypes, parse_query_func parser = raw_parser); +extern SPIPlanPtr SPI_prepare_cursor(const char* src, int nargs, Oid* argtypes, int cursorOptions, parse_query_func parser = raw_parser); +extern SPIPlanPtr SPI_prepare_params(const char* src, ParserSetupHook parserSetup, void* parserSetupArg, int cursorOptions, parse_query_func parser = raw_parser); extern int SPI_keepplan(SPIPlanPtr plan); extern SPIPlanPtr SPI_saveplan(SPIPlanPtr plan); extern int SPI_freeplan(SPIPlanPtr plan); @@ -125,7 +128,7 @@ extern void SPI_freetuptable(SPITupleTable* tuptable); extern Portal SPI_cursor_open(const char* name, SPIPlanPtr plan, Datum* Values, const char* Nulls, bool read_only); extern Portal SPI_cursor_open_with_args(const char* name, const char* src, int nargs, Oid* argtypes, Datum* Values, - const char* Nulls, bool read_only, int cursorOptions); + const char* Nulls, bool read_only, int cursorOptions, parse_query_func parser = raw_parser); extern Portal SPI_cursor_open_with_paramlist(const char* name, SPIPlanPtr plan, ParamListInfo params, bool read_only, bool isCollectParam = false); extern Portal SPI_cursor_find(const char* name); @@ -152,23 +155,23 @@ extern DestReceiver* createAnalyzeSPIDestReceiver(CommandDest dest); extern void ReleaseSpiPlanRef(); /* SPI execution helpers */ extern void spi_exec_with_callback(CommandDest dest, const char* src, bool read_only, long tcount, bool direct_call, - void (*callbackFn)(void*), void* clientData); + void (*callbackFn)(void*), void* clientData, parse_query_func parser = raw_parser); extern void _SPI_error_callback(void *arg); extern List* _SPI_get_querylist(SPIPlanPtr plan); #ifdef PGXC -extern int SPI_execute_direct(const char* src, char* nodename); +extern int SPI_execute_direct(const char* src, char* nodename, parse_query_func parser = raw_parser); #endif extern int _SPI_begin_call(bool execmem); extern int _SPI_end_call(bool procmem); extern void _SPI_hold_cursor(); -extern void _SPI_prepare_oneshot_plan_for_validator(const char* src, SPIPlanPtr plan); +extern void _SPI_prepare_oneshot_plan_for_validator(const char* src, SPIPlanPtr plan, parse_query_func parser = raw_parser); extern void InitSPIPlanCxt(); -extern void _SPI_prepare_plan(const char *src, SPIPlanPtr plan); +extern void _SPI_prepare_plan(const char *src, SPIPlanPtr plan, parse_query_func parser = raw_parser); extern ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls, Cursor_Data *cursor_data = NULL); -extern void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan); +extern void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan, parse_query_func parser = raw_parser); extern int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, long tcount, bool from_lock = false); diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 60a99ee11..7a92f7d2c 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -36,7 +36,8 @@ typedef enum { LOGSTMT_ALL /* log all statements */ } LogStmtLevel; -extern List* pg_parse_query(const char* query_string, List** query_string_locationlist = NULL); +extern List* pg_parse_query(const char* query_string, List** query_string_locationlist = NULL, + List* (*parser_hook)(const char*, List**) = NULL); extern List* pg_analyze_and_rewrite(Node* parsetree, const char* query_string, Oid* paramTypes, int numParams); extern List* pg_analyze_and_rewrite_params( Node* parsetree, const char* query_string, ParserSetupHook parserSetup, void* parserSetupArg);