There are a couple of function call overheads I observed in pl/pgsql code : exec_stmt() and exec_cast_value(). Removing these overheads resulted in some performance gains.
exec_stmt() : plpgsql_exec_function() and other toplevel block executors currently call exec_stmt(). But actually they don't need to do everything that exec_stmt() does. So they can call a new function instead of exec_stmt(), and all the exec_stmt() code can be moved to exec_stmts(). The things that exec_stmt() do, but are not necessary for a top level block stmt, are : 1. save_estmt = estate->err_stmt; estate->err_stmt = stmt; For top level blocks, saving the estate->err_stmt is not necessary, because there is no statement after this block statement. Anyways, plpgsql_exec_function() assigns estate.err_stmt just before calling exec_stmt so there is really no point in exec_stmt() setting it again. 2. CHECK_FOR_INTERRUPTS() This is not necessary for toplevel block callers. 3. exec_stmt_block() can be directly called rather than exec_stmt() because func->action is a block statement. So the switch statement is not necessary. But this one might be necessary for toplevel block statement: if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg) ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt); There was already a repetitive code in plpgsql_exec_function() and other functions around the exec_stmt() call. So in a separate patch 0001*.patch, I moved that code into a common function exec_toplevel_block(). In the main patch 0002-Get-rid-of-exec_stmt-function-call.patch, I additionally called plpgsql_plugin_ptr->stmt_beg() inside exec_toplevel_block(). And moved exec_stmt() code into exec_stmts(). exec_cast_value() : This function does not do the casting if not required. So moved the code that actually does the cast into a separate function, so as to reduce the exec_cast_value() code and make it inline. Attached is the 0003-Inline-exec_cast_value.patch Testing ---------- I used two available VMs (one x86_64 and the other arm64), and the benefit showed up on both of these machines. Attached patches 0001, 0002, 0003 are to be applied in that order. 0001 is just a preparatory patch. First I tried with a simple for loop with a single assignment (attached forcounter.sql) By inlining of the two functions, found noticeable reduction in execution time as shown (figures are in milliseconds, averaged over multiple runs; taken from 'explain analyze' execution times) : ARM VM : HEAD : 100 ; Patched : 88 => 13.6% improvement x86 VM : HEAD : 71 ; Patched : 66 => 7.63% improvement. Then I included many assignment statements as shown in attachment assignmany.sql. This showed further benefit : ARM VM : HEAD : 1820 ; Patched : 1549 => 17.5% improvement x86 VM : HEAD : 1020 ; Patched : 869 => 17.4% improvement Inlining just exec_stmt() showed the improvement mainly on the arm64 VM (7.4%). For x86, it was 2.7% But inlining exec_stmt() and exec_cast_value() together showed benefits on both machines, as can be seen above. -- Thanks, -Amit Khandekar Huawei Technologies
From 66c607ef6f0b7b655819b4b19383e024c5f8788c Mon Sep 17 00:00:00 2001 From: Amit Khandekar <amitdkhan...@gmail.com> Date: Sat, 23 May 2020 21:39:41 +0800 Subject: [PATCH 1/3] Modularize code in toplevel pl/pgsql block callers Functions that call exec_stmt() for executing the toplevel block have a repetitive code that is now moved into a common function exec_toplevel_block(). This in preparation for further changes in this part of code. --- src/pl/plpgsql/src/pl_exec.c | 86 ++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 9a87cd70f1..0a70ceddbb 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -267,6 +267,9 @@ static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate); static void push_stmt_mcontext(PLpgSQL_execstate *estate); static void pop_stmt_mcontext(PLpgSQL_execstate *estate); +static void exec_toplevel_block(PLpgSQL_execstate *estate, + PLpgSQL_stmt_block *block, + char *object_type, char *err_text); static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block); static int exec_stmts(PLpgSQL_execstate *estate, @@ -475,7 +478,6 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, PLpgSQL_execstate estate; ErrorContextCallback plerrcontext; int i; - int rc; /* * Setup the execution state @@ -605,23 +607,8 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, /* * Now call the toplevel block of statements */ - estate.err_text = NULL; - estate.err_stmt = (PLpgSQL_stmt *) (func->action); - rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action); - if (rc != PLPGSQL_RC_RETURN) - { - estate.err_stmt = NULL; - estate.err_text = NULL; - ereport(ERROR, - (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - errmsg("control reached end of function without RETURN"))); - } - - /* - * We got a return value - process it - */ - estate.err_stmt = NULL; - estate.err_text = gettext_noop("while casting return value to function's return type"); + exec_toplevel_block(&estate, func->action, "function", + gettext_noop("while casting return value to function's return type")); fcinfo->isnull = estate.retisnull; @@ -909,7 +896,7 @@ plpgsql_exec_trigger(PLpgSQL_function *func, { PLpgSQL_execstate estate; ErrorContextCallback plerrcontext; - int rc; + int rc PG_USED_FOR_ASSERTS_ONLY; TupleDesc tupdesc; PLpgSQL_rec *rec_new, *rec_old; @@ -1021,20 +1008,8 @@ plpgsql_exec_trigger(PLpgSQL_function *func, /* * Now call the toplevel block of statements */ - estate.err_text = NULL; - estate.err_stmt = (PLpgSQL_stmt *) (func->action); - rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action); - if (rc != PLPGSQL_RC_RETURN) - { - estate.err_stmt = NULL; - estate.err_text = NULL; - ereport(ERROR, - (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - errmsg("control reached end of trigger procedure without RETURN"))); - } - - estate.err_stmt = NULL; - estate.err_text = gettext_noop("during function exit"); + exec_toplevel_block(&estate, func->action, "trigger procedure", + gettext_noop("during function exit")); if (estate.retisset) ereport(ERROR, @@ -1151,7 +1126,6 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata) { PLpgSQL_execstate estate; ErrorContextCallback plerrcontext; - int rc; /* * Setup the execution state @@ -1182,20 +1156,8 @@ plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata) /* * Now call the toplevel block of statements */ - estate.err_text = NULL; - estate.err_stmt = (PLpgSQL_stmt *) (func->action); - rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action); - if (rc != PLPGSQL_RC_RETURN) - { - estate.err_stmt = NULL; - estate.err_text = NULL; - ereport(ERROR, - (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - errmsg("control reached end of trigger procedure without RETURN"))); - } - - estate.err_stmt = NULL; - estate.err_text = gettext_noop("during function exit"); + exec_toplevel_block(&estate, func->action, "trigger procedure", + gettext_noop("during function exit")); /* * Let the instrumentation plugin peek at this function @@ -1591,6 +1553,34 @@ exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond) } +/* ---------- + * exec_toplevel_block Execute the toplevel block + * ---------- + */ +static void +exec_toplevel_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block, + char *object_type, char *err_text) +{ + int rc; + + estate->err_text = NULL; + estate->err_stmt = (PLpgSQL_stmt *)block; + + rc = exec_stmt(estate, (PLpgSQL_stmt *)block); + + if (rc != PLPGSQL_RC_RETURN) + { + estate->err_stmt = NULL; + estate->err_text = NULL; + ereport(ERROR, + (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), + errmsg("control reached end of %s without RETURN", object_type))); + } + + estate->err_stmt = NULL; + estate->err_text = err_text; +} + /* ---------- * exec_stmt_block Execute a block of statements * ---------- -- 2.17.1
From ff9906d78c5c59c296b7a9ecfefd8715f29a0fe0 Mon Sep 17 00:00:00 2001 From: Amit Khandekar <amitdkhan...@gmail.com> Date: Sat, 23 May 2020 21:44:28 +0800 Subject: [PATCH 2/3] Get rid of exec_stmt() function call Reduce exec_stmt() callers and move its code into exec_stmts(). All other callers of exec_stmt() were toplevel block executors. These don't need to exec_stmt(); they can directly call exec_stmt_block(). This reduces funtion call overhead because exec_stmt() is called frequently. This is shown to obtain as much as 7% performance benefit on some systems. --- src/pl/plpgsql/src/pl_exec.c | 236 +++++++++++++++++------------------ 1 file changed, 114 insertions(+), 122 deletions(-) diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 0a70ceddbb..d5377a6dad 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -274,8 +274,6 @@ static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block); static int exec_stmts(PLpgSQL_execstate *estate, List *stmts); -static int exec_stmt(PLpgSQL_execstate *estate, - PLpgSQL_stmt *stmt); static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt); static int exec_stmt_perform(PLpgSQL_execstate *estate, @@ -1566,7 +1564,15 @@ exec_toplevel_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block, estate->err_text = NULL; estate->err_stmt = (PLpgSQL_stmt *)block; - rc = exec_stmt(estate, (PLpgSQL_stmt *)block); + /* Let the plugin know that we are about to execute this statement */ + if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg) + ((*plpgsql_plugin_ptr)->stmt_beg) (estate, (PLpgSQL_stmt *)block); + + rc = exec_stmt_block(estate, block); + + /* Let the plugin know that we have finished executing this statement */ + if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end) + ((*plpgsql_plugin_ptr)->stmt_end) (estate, (PLpgSQL_stmt *)block); if (rc != PLPGSQL_RC_RETURN) { @@ -1930,162 +1936,148 @@ exec_stmts(PLpgSQL_execstate *estate, List *stmts) foreach(s, stmts) { PLpgSQL_stmt *stmt = (PLpgSQL_stmt *) lfirst(s); - int rc = exec_stmt(estate, stmt); + PLpgSQL_stmt *save_estmt; + int rc = -1; - if (rc != PLPGSQL_RC_OK) - return rc; - } - - return PLPGSQL_RC_OK; -} + save_estmt = estate->err_stmt; + estate->err_stmt = stmt; + /* Let the plugin know that we are about to execute this statement */ + if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg) + ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt); -/* ---------- - * exec_stmt Distribute one statement to the statements - * type specific execution function. - * ---------- - */ -static int -exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt) -{ - PLpgSQL_stmt *save_estmt; - int rc = -1; + CHECK_FOR_INTERRUPTS(); - save_estmt = estate->err_stmt; - estate->err_stmt = stmt; + switch (stmt->cmd_type) + { + case PLPGSQL_STMT_BLOCK: + rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt); + break; - /* Let the plugin know that we are about to execute this statement */ - if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg) - ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt); + case PLPGSQL_STMT_ASSIGN: + rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt); + break; - CHECK_FOR_INTERRUPTS(); + case PLPGSQL_STMT_PERFORM: + rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt); + break; - switch (stmt->cmd_type) - { - case PLPGSQL_STMT_BLOCK: - rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt); - break; + case PLPGSQL_STMT_CALL: + rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt); + break; - case PLPGSQL_STMT_ASSIGN: - rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt); - break; + case PLPGSQL_STMT_GETDIAG: + rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt); + break; - case PLPGSQL_STMT_PERFORM: - rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt); - break; + case PLPGSQL_STMT_IF: + rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt); + break; - case PLPGSQL_STMT_CALL: - rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt); - break; + case PLPGSQL_STMT_CASE: + rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt); + break; - case PLPGSQL_STMT_GETDIAG: - rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt); - break; + case PLPGSQL_STMT_LOOP: + rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt); + break; - case PLPGSQL_STMT_IF: - rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt); - break; + case PLPGSQL_STMT_WHILE: + rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt); + break; - case PLPGSQL_STMT_CASE: - rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt); - break; + case PLPGSQL_STMT_FORI: + rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt); + break; - case PLPGSQL_STMT_LOOP: - rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt); - break; + case PLPGSQL_STMT_FORS: + rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt); + break; - case PLPGSQL_STMT_WHILE: - rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt); - break; + case PLPGSQL_STMT_FORC: + rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt); + break; - case PLPGSQL_STMT_FORI: - rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt); - break; + case PLPGSQL_STMT_FOREACH_A: + rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt); + break; - case PLPGSQL_STMT_FORS: - rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt); - break; + case PLPGSQL_STMT_EXIT: + rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt); + break; - case PLPGSQL_STMT_FORC: - rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt); - break; + case PLPGSQL_STMT_RETURN: + rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt); + break; - case PLPGSQL_STMT_FOREACH_A: - rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt); - break; + case PLPGSQL_STMT_RETURN_NEXT: + rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt); + break; - case PLPGSQL_STMT_EXIT: - rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt); - break; + case PLPGSQL_STMT_RETURN_QUERY: + rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt); + break; - case PLPGSQL_STMT_RETURN: - rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt); - break; + case PLPGSQL_STMT_RAISE: + rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt); + break; - case PLPGSQL_STMT_RETURN_NEXT: - rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt); - break; + case PLPGSQL_STMT_ASSERT: + rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt); + break; - case PLPGSQL_STMT_RETURN_QUERY: - rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt); - break; + case PLPGSQL_STMT_EXECSQL: + rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt); + break; - case PLPGSQL_STMT_RAISE: - rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt); - break; + case PLPGSQL_STMT_DYNEXECUTE: + rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt); + break; - case PLPGSQL_STMT_ASSERT: - rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt); - break; + case PLPGSQL_STMT_DYNFORS: + rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt); + break; - case PLPGSQL_STMT_EXECSQL: - rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt); - break; + case PLPGSQL_STMT_OPEN: + rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt); + break; - case PLPGSQL_STMT_DYNEXECUTE: - rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt); - break; + case PLPGSQL_STMT_FETCH: + rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt); + break; - case PLPGSQL_STMT_DYNFORS: - rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt); - break; + case PLPGSQL_STMT_CLOSE: + rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt); + break; - case PLPGSQL_STMT_OPEN: - rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt); - break; + case PLPGSQL_STMT_COMMIT: + rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt); + break; - case PLPGSQL_STMT_FETCH: - rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt); - break; + case PLPGSQL_STMT_ROLLBACK: + rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt); + break; - case PLPGSQL_STMT_CLOSE: - rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt); - break; + case PLPGSQL_STMT_SET: + rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt); + break; - case PLPGSQL_STMT_COMMIT: - rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt); - break; + default: + estate->err_stmt = save_estmt; + elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); + } - case PLPGSQL_STMT_ROLLBACK: - rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt); - break; + /* Let the plugin know that we have finished executing this statement */ + if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end) + ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt); - case PLPGSQL_STMT_SET: - rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt); - break; + estate->err_stmt = save_estmt; - default: - estate->err_stmt = save_estmt; - elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); + if (rc != PLPGSQL_RC_OK) + return rc; } - /* Let the plugin know that we have finished executing this statement */ - if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end) - ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt); - - estate->err_stmt = save_estmt; - - return rc; + return PLPGSQL_RC_OK; } -- 2.17.1
From 56aac7dff8243ff6dc9b8e72651cb1d9a018f1b3 Mon Sep 17 00:00:00 2001 From: Amit Khandekar <amitdkhan...@gmail.com> Date: Sat, 23 May 2020 21:53:24 +0800 Subject: [PATCH 3/3] Inline exec_cast_value(). This function does not do the casting if not required. So move the code that actually does the cast into a separate function, so as to reduce the exec_cast_value() code and make it inline. There are frequent calls of this function, so inlining it has shown to improve performance by as much as 14% --- src/pl/plpgsql/src/pl_exec.c | 63 ++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index d5377a6dad..4028a3f0f6 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -425,10 +425,14 @@ static void instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec); static char *convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype); -static Datum exec_cast_value(PLpgSQL_execstate *estate, +static inline Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, Oid reqtype, int32 reqtypmod); +static Datum do_cast_value(PLpgSQL_execstate *estate, + Datum value, bool *isnull, + Oid valtype, int32 valtypmod, + Oid reqtype, int32 reqtypmod); static plpgsql_CastHashEntry *get_cast_hashentry(PLpgSQL_execstate *estate, Oid srctype, int32 srctypmod, Oid dsttype, int32 dsttypmod); @@ -7764,9 +7768,11 @@ convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype) * also contain the result Datum if we have to do a conversion to a pass- * by-reference data type. Be sure to do an exec_eval_cleanup() call when * done with the result. + * The actual code to cast is kept outside of this function, to keep it short + * since it is an inline function, being called frequently. * ---------- */ -static Datum +static inline Datum exec_cast_value(PLpgSQL_execstate *estate, Datum value, bool *isnull, Oid valtype, int32 valtypmod, @@ -7777,31 +7783,48 @@ exec_cast_value(PLpgSQL_execstate *estate, */ if (valtype != reqtype || (valtypmod != reqtypmod && reqtypmod != -1)) - { - plpgsql_CastHashEntry *cast_entry; + value = do_cast_value(estate, value, isnull, valtype, valtypmod, + reqtype, reqtypmod); - cast_entry = get_cast_hashentry(estate, - valtype, valtypmod, - reqtype, reqtypmod); - if (cast_entry) - { - ExprContext *econtext = estate->eval_econtext; - MemoryContext oldcontext; + return value; +} - oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); +/* ---------- + * do_cast_value cast the input value. + * + * Returns the cast value. + * Check comments in the wrapper function exec_cast_value(). + * ---------- + */ +static Datum +do_cast_value(PLpgSQL_execstate *estate, + Datum value, bool *isnull, + Oid valtype, int32 valtypmod, + Oid reqtype, int32 reqtypmod) +{ + plpgsql_CastHashEntry *cast_entry; - econtext->caseValue_datum = value; - econtext->caseValue_isNull = *isnull; + cast_entry = get_cast_hashentry(estate, + valtype, valtypmod, + reqtype, reqtypmod); + if (cast_entry) + { + ExprContext *econtext = estate->eval_econtext; + MemoryContext oldcontext; - cast_entry->cast_in_use = true; + oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); - value = ExecEvalExpr(cast_entry->cast_exprstate, econtext, - isnull); + econtext->caseValue_datum = value; + econtext->caseValue_isNull = *isnull; - cast_entry->cast_in_use = false; + cast_entry->cast_in_use = true; - MemoryContextSwitchTo(oldcontext); - } + value = ExecEvalExpr(cast_entry->cast_exprstate, econtext, + isnull); + + cast_entry->cast_in_use = false; + + MemoryContextSwitchTo(oldcontext); } return value; -- 2.17.1
forcounter.sql
Description: application/sql
assignmany.sql
Description: application/sql