|
29 | 29 | #include "mb/stringinfo_mb.h" |
30 | 30 | #include "miscadmin.h" |
31 | 31 | #include "nodes/nodeFuncs.h" |
| 32 | +#include "nodes/supportnodes.h" |
32 | 33 | #include "optimizer/optimizer.h" |
33 | 34 | #include "parser/parse_coerce.h" |
34 | 35 | #include "parser/parse_type.h" |
@@ -8411,7 +8412,7 @@ exec_check_rw_parameter(PLpgSQL_expr *expr, int paramid) |
8411 | 8412 | Expr *sexpr = expr->expr_simple_expr; |
8412 | 8413 | Oid funcid; |
8413 | 8414 | List *fargs; |
8414 | | - ListCell *lc; |
| 8415 | + Oid prosupport; |
8415 | 8416 |
|
8416 | 8417 | /* Assume unsafe */ |
8417 | 8418 | expr->expr_rwopt = PLPGSQL_RWOPT_NOPE; |
@@ -8480,64 +8481,51 @@ exec_check_rw_parameter(PLpgSQL_expr *expr, int paramid) |
8480 | 8481 | { |
8481 | 8482 | SubscriptingRef *sbsref = (SubscriptingRef *) sexpr; |
8482 | 8483 |
|
8483 | | - /* We only trust standard varlena arrays to be safe */ |
8484 | | - /* TODO: install some extensibility here */ |
8485 | | - if (get_typsubscript(sbsref->refcontainertype, NULL) != |
8486 | | - F_ARRAY_SUBSCRIPT_HANDLER) |
8487 | | - return; |
8488 | | - |
8489 | | - /* We can optimize the refexpr if it's the target, otherwise not */ |
8490 | | - if (sbsref->refexpr && IsA(sbsref->refexpr, Param)) |
8491 | | - { |
8492 | | - Param *param = (Param *) sbsref->refexpr; |
| 8484 | + funcid = get_typsubscript(sbsref->refcontainertype, NULL); |
8493 | 8485 |
|
8494 | | - if (param->paramkind == PARAM_EXTERN && |
8495 | | - param->paramid == paramid) |
8496 | | - { |
8497 | | - /* Found the Param we want to pass as read/write */ |
8498 | | - expr->expr_rwopt = PLPGSQL_RWOPT_INPLACE; |
8499 | | - expr->expr_rw_param = param; |
8500 | | - return; |
8501 | | - } |
8502 | | - } |
8503 | | - |
8504 | | - return; |
| 8486 | + /* |
| 8487 | + * We assume that only the refexpr and refassgnexpr (if any) are |
| 8488 | + * relevant to the support function's decision. If that turns out to |
| 8489 | + * be a bad idea, we could incorporate the subscript expressions into |
| 8490 | + * the fargs list somehow. |
| 8491 | + */ |
| 8492 | + fargs = list_make2(sbsref->refexpr, sbsref->refassgnexpr); |
8505 | 8493 | } |
8506 | 8494 | else |
8507 | 8495 | return; |
8508 | 8496 |
|
8509 | 8497 | /* |
8510 | | - * The top-level function must be one that we trust to be "safe". |
8511 | | - * Currently we hard-wire the list, but it would be very desirable to |
8512 | | - * allow extensions to mark their functions as safe ... |
| 8498 | + * The top-level function must be one that can handle in-place update |
| 8499 | + * safely. We allow functions to declare their ability to do that via a |
| 8500 | + * support function request. |
8513 | 8501 | */ |
8514 | | - if (!(funcid == F_ARRAY_APPEND || |
8515 | | - funcid == F_ARRAY_PREPEND)) |
8516 | | - return; |
8517 | | - |
8518 | | - /* |
8519 | | - * The target variable (in the form of a Param) must appear as a direct |
8520 | | - * argument of the top-level function. References further down in the |
8521 | | - * tree can't be optimized; but on the other hand, they don't invalidate |
8522 | | - * optimizing the top-level call, since that will be executed last. |
8523 | | - */ |
8524 | | - foreach(lc, fargs) |
| 8502 | + prosupport = get_func_support(funcid); |
| 8503 | + if (OidIsValid(prosupport)) |
8525 | 8504 | { |
8526 | | - Node *arg = (Node *) lfirst(lc); |
| 8505 | + SupportRequestModifyInPlace req; |
| 8506 | + Param *param; |
8527 | 8507 |
|
8528 | | - if (arg && IsA(arg, Param)) |
8529 | | - { |
8530 | | - Param *param = (Param *) arg; |
| 8508 | + req.type = T_SupportRequestModifyInPlace; |
| 8509 | + req.funcid = funcid; |
| 8510 | + req.args = fargs; |
| 8511 | + req.paramid = paramid; |
8531 | 8512 |
|
8532 | | - if (param->paramkind == PARAM_EXTERN && |
8533 | | - param->paramid == paramid) |
8534 | | - { |
8535 | | - /* Found the Param we want to pass as read/write */ |
8536 | | - expr->expr_rwopt = PLPGSQL_RWOPT_INPLACE; |
8537 | | - expr->expr_rw_param = param; |
8538 | | - return; |
8539 | | - } |
8540 | | - } |
| 8513 | + param = (Param *) |
| 8514 | + DatumGetPointer(OidFunctionCall1(prosupport, |
| 8515 | + PointerGetDatum(&req))); |
| 8516 | + |
| 8517 | + if (param == NULL) |
| 8518 | + return; /* support function fails */ |
| 8519 | + |
| 8520 | + /* Verify support function followed the API */ |
| 8521 | + Assert(IsA(param, Param)); |
| 8522 | + Assert(param->paramkind == PARAM_EXTERN); |
| 8523 | + Assert(param->paramid == paramid); |
| 8524 | + |
| 8525 | + /* Found the Param we want to pass as read/write */ |
| 8526 | + expr->expr_rwopt = PLPGSQL_RWOPT_INPLACE; |
| 8527 | + expr->expr_rw_param = param; |
| 8528 | + return; |
8541 | 8529 | } |
8542 | 8530 | } |
8543 | 8531 |
|
|
0 commit comments