diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 246776093e..be634b87e7 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -625,6 +625,7 @@ AggregateCreate(const char *aggName, PROVOLATILE_IMMUTABLE, /* volatility (not needed * for agg) */ proparallel, + false, /* isPrivate, now false */ parameterTypes, /* paramTypes */ allParameterTypes, /* allParamTypes */ parameterModes, /* parameterModes */ @@ -798,6 +799,8 @@ lookup_agg_function(List *fnName, FuncDetailCode fdresult; AclResult aclresult; int i; + bool is_private; + Oid nspid; /* * func_get_detail looks up the function in the catalogs, does @@ -810,7 +813,8 @@ lookup_agg_function(List *fnName, nargs, input_types, false, false, &fnOid, rettype, &retset, &nvargs, &vatype, - &true_oid_array, NULL); + &true_oid_array, NULL, + &is_private, &nspid); /* only valid case is a normal function not returning a set */ if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid)) diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 9b4015d0d4..4b11485442 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -79,6 +79,7 @@ ProcedureCreate(const char *procedureName, bool isStrict, char volatility, char parallel, + bool isPrivate, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, @@ -329,6 +330,7 @@ ProcedureCreate(const char *procedureName, values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults)); values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType); values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes); + values[Anum_pg_proc_proisprivate - 1] = BoolGetDatum(isPrivate); if (allParameterTypes != PointerGetDatum(NULL)) values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes; else diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 68109bfda0..51907dd678 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -479,7 +479,8 @@ compute_common_attribute(ParseState *pstate, List **set_items, DefElem **cost_item, DefElem **rows_item, - DefElem **parallel_item) + DefElem **parallel_item, + DefElem **scope_item) { if (strcmp(defel->defname, "volatility") == 0) { @@ -546,6 +547,13 @@ compute_common_attribute(ParseState *pstate, *parallel_item = defel; } + else if (strcmp(defel->defname, "scope") == 0) + { + if (*scope_item) + goto duplicate_error; + + *scope_item = defel; + } else return false; @@ -655,7 +663,8 @@ compute_function_attributes(ParseState *pstate, ArrayType **proconfig, float4 *procost, float4 *prorows, - char *parallel_p) + char *parallel_p, + bool *isPrivate) { ListCell *option; DefElem *as_item = NULL; @@ -670,6 +679,7 @@ compute_function_attributes(ParseState *pstate, DefElem *cost_item = NULL; DefElem *rows_item = NULL; DefElem *parallel_item = NULL; + DefElem *scope_item = NULL; foreach(option, options) { @@ -726,7 +736,8 @@ compute_function_attributes(ParseState *pstate, &set_items, &cost_item, &rows_item, - ¶llel_item)) + ¶llel_item, + &scope_item)) { /* recognized common option */ continue; @@ -790,6 +801,11 @@ compute_function_attributes(ParseState *pstate, } if (parallel_item) *parallel_p = interpret_func_parallel(parallel_item); + if (scope_item) + { + if (strcmp(strVal(scope_item->arg), "private") == 0) + *isPrivate = true; + } } @@ -889,6 +905,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) isStrict, security, isLeakProof; + bool isPrivate; char volatility; ArrayType *proconfig; float4 procost; @@ -918,6 +935,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) procost = -1; /* indicates not set */ prorows = -1; /* indicates not set */ parallel = PROPARALLEL_UNSAFE; + isPrivate = false; /* Extract non-default attributes from stmt->options list */ compute_function_attributes(pstate, @@ -926,7 +944,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) &as_clause, &language, &transformDefElem, &isWindowFunc, &volatility, &isStrict, &security, &isLeakProof, - &proconfig, &procost, &prorows, ¶llel); + &proconfig, &procost, &prorows, ¶llel, + &isPrivate); /* Look up the language and validate permissions */ languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language)); @@ -1106,6 +1125,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) isStrict, volatility, parallel, + isPrivate, parameterTypes, PointerGetDatum(allParameterTypes), PointerGetDatum(parameterModes), @@ -1188,6 +1208,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) DefElem *cost_item = NULL; DefElem *rows_item = NULL; DefElem *parallel_item = NULL; + DefElem *scope_item = NULL; ObjectAddress address; rel = heap_open(ProcedureRelationId, RowExclusiveLock); @@ -1228,7 +1249,8 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) &set_items, &cost_item, &rows_item, - ¶llel_item) == false) + ¶llel_item, + &scope_item) == false) elog(ERROR, "option \"%s\" not recognized", defel->defname); } diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index c900ad9431..35dd0a619a 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -134,6 +134,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) false, /* isStrict */ PROVOLATILE_VOLATILE, PROPARALLEL_UNSAFE, + false, /* isPrivate */ buildoidvector(funcargtypes, 0), PointerGetDatum(NULL), PointerGetDatum(NULL), @@ -173,6 +174,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) true, /* isStrict */ PROVOLATILE_VOLATILE, PROPARALLEL_UNSAFE, + false, /* isPrivate */ buildoidvector(funcargtypes, 1), PointerGetDatum(NULL), PointerGetDatum(NULL), @@ -215,6 +217,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) true, /* isStrict */ PROVOLATILE_VOLATILE, PROPARALLEL_UNSAFE, + false, /* isPrivate */ buildoidvector(funcargtypes, 1), PointerGetDatum(NULL), PointerGetDatum(NULL), diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 175ecc8b48..9525b766a1 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -1675,6 +1675,7 @@ makeRangeConstructors(const char *name, Oid namespace, false, /* isStrict */ PROVOLATILE_IMMUTABLE, /* volatility */ PROPARALLEL_SAFE, /* parallel safety */ + false, /* isPrivate */ constructorArgTypesVector, /* parameterTypes */ PointerGetDatum(NULL), /* allParameterTypes */ PointerGetDatum(NULL), /* parameterModes */ diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index e284fd71d7..54ba40d2d0 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -153,7 +153,7 @@ ExecInitExpr(Expr *node, PlanState *parent) * and instead we may have a ParamListInfo describing PARAM_EXTERN Params. */ ExprState * -ExecInitExprWithParams(Expr *node, ParamListInfo ext_params) +ExecInitExprWithParams(Expr *node, ParamListInfo ext_params, Oid query_owner_nspid) { ExprState *state; ExprEvalStep scratch = {0}; @@ -167,6 +167,7 @@ ExecInitExprWithParams(Expr *node, ParamListInfo ext_params) state->expr = node; state->parent = NULL; state->ext_params = ext_params; + state->query_owner_nspid = query_owner_nspid; /* Insert EEOP_*_FETCHSOME steps as needed */ ExecInitExprSlots(state, (Node *) node); @@ -879,6 +880,25 @@ ExecInitExprRec(Expr *node, ExprState *state, { FuncExpr *func = (FuncExpr *) node; + /* check scope of function */ + if (func->funcprivate) + { + Oid query_owner_nspid = state->query_owner_nspid; + + if (OidIsValid(state->query_owner_nspid)) + query_owner_nspid = state->query_owner_nspid; + else if (state->parent && state->parent->state) + query_owner_nspid = + state->parent->state->es_query_owner_nspid; + + if (!OidIsValid(query_owner_nspid)) + elog(ERROR, "private function can be called only from routine"); + if (query_owner_nspid != func->funcnspid) + elog(ERROR, "private function of \"%s\" used from function from \"%s\"", + get_namespace_name(func->funcnspid), + get_namespace_name(query_owner_nspid)); + } + ExecInitFunc(&scratch, node, func->args, func->funcid, func->inputcollid, state); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index c583e020a0..00ca74a804 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -824,6 +824,9 @@ InitPlan(QueryDesc *queryDesc, int eflags) estate->es_range_table = rangeTable; estate->es_plannedstmt = plannedstmt; + /* ToDo: Better to store query_owner_nspid to QueryDesc */ + estate->es_query_owner_nspid = plannedstmt->query_owner_nspid; + /* * initialize result relation stuff, and open/lock the result rels. * diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index ee0f07a81e..ec88d8160e 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -1102,6 +1102,7 @@ ExecParallelGetQueryDesc(shm_toc *toc, DestReceiver *receiver, PlannedStmt *pstmt; ParamListInfo paramLI; char *queryString; + Oid query_owner_nspid; /* Get the query string from shared memory */ queryString = shm_toc_lookup(toc, PARALLEL_KEY_QUERY_TEXT, false); diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 5b3eaec80b..8b7d52bf57 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -159,6 +159,8 @@ CreateExecutorState(void) estate->es_use_parallel_mode = false; + estate->es_query_owner_nspid = InvalidOid; + estate->es_jit_flags = 0; estate->es_jit = NULL; diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 5756365c8f..6c01be90b9 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -2149,6 +2149,9 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, _SPI_current->lastoid = InvalidOid; _SPI_current->tuptable = NULL; + /* inject assigned query_owner_nspid */ + stmt->query_owner_nspid = plan->query_owner_nspid; + if (stmt->utilityStmt) { if (IsA(stmt->utilityStmt, CopyStmt)) @@ -2200,6 +2203,11 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, else snap = InvalidSnapshot; + /* + * ToDo: better place to inject query owner nspid, but + * we should to implement passing query owner nspid over + * parallel workers. + */ qdesc = CreateQueryDesc(stmt, plansource->query_string, snap, crosscheck_snapshot, @@ -2697,6 +2705,8 @@ _SPI_make_plan_non_temp(SPIPlanPtr plan) /* For safety, unlink the CachedPlanSources from the temporary plan */ plan->plancache_list = NIL; + newplan->query_owner_nspid = plan->query_owner_nspid; + return newplan; } @@ -2767,9 +2777,21 @@ _SPI_save_plan(SPIPlanPtr plan) SaveCachedPlan(plansource); } + newplan->query_owner_nspid = plan->query_owner_nspid; + return newplan; } +/* + * Assign query owner namespace to plan. The query owner nspid + * is used for implementation of schema private functions. + */ +void +assign_query_owner_nspid(SPIPlanPtr plan, Oid query_owner_nspid) +{ + plan->query_owner_nspid = query_owner_nspid; +} + /* * Internal lookup of ephemeral named relation by name. */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 7c8220cf65..b52f287c35 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -102,6 +102,7 @@ _copyPlannedStmt(const PlannedStmt *from) COPY_NODE_FIELD(utilityStmt); COPY_LOCATION_FIELD(stmt_location); COPY_LOCATION_FIELD(stmt_len); + COPY_SCALAR_FIELD(query_owner_nspid); return newnode; } @@ -1524,6 +1525,8 @@ _copyFuncExpr(const FuncExpr *from) COPY_SCALAR_FIELD(funccollid); COPY_SCALAR_FIELD(inputcollid); COPY_NODE_FIELD(args); + COPY_SCALAR_FIELD(funcprivate); + COPY_SCALAR_FIELD(funcnspid); COPY_LOCATION_FIELD(location); return newnode; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 378f2facb8..144034760f 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -289,6 +289,8 @@ _equalFuncExpr(const FuncExpr *a, const FuncExpr *b) COMPARE_SCALAR_FIELD(funccollid); COMPARE_SCALAR_FIELD(inputcollid); COMPARE_NODE_FIELD(args); + COMPARE_SCALAR_FIELD(funcprivate); + COMPARE_SCALAR_FIELD(funcnspid); COMPARE_LOCATION_FIELD(location); return true; diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 1bd2599c2c..2e78dd8f18 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -526,6 +526,8 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args, funcexpr->funcresulttype = rettype; funcexpr->funcretset = false; /* only allowed case here */ funcexpr->funcvariadic = false; /* only allowed case here */ + funcexpr->funcprivate = false; /* only allowed case here */ + funcexpr->funcnspid = InvalidOid; funcexpr->funcformat = fformat; funcexpr->funccollid = funccollid; funcexpr->inputcollid = inputcollid; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 6269f474d2..6a8cb3af23 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -287,6 +287,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node) WRITE_NODE_FIELD(utilityStmt); WRITE_LOCATION_FIELD(stmt_location); WRITE_LOCATION_FIELD(stmt_len); + WRITE_OID_FIELD(query_owner_nspid); } /* @@ -1278,6 +1279,8 @@ _outFuncExpr(StringInfo str, const FuncExpr *node) WRITE_OID_FIELD(funccollid); WRITE_OID_FIELD(inputcollid); WRITE_NODE_FIELD(args); + WRITE_BOOL_FIELD(funcprivate); + WRITE_OID_FIELD(funcnspid); WRITE_LOCATION_FIELD(location); } diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 3254524223..7cde1caf47 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -680,6 +680,8 @@ _readFuncExpr(void) READ_OID_FIELD(funccollid); READ_OID_FIELD(inputcollid); READ_NODE_FIELD(args); + READ_BOOL_FIELD(funcprivate); + READ_OID_FIELD(funcnspid); READ_LOCATION_FIELD(location); READ_DONE(); @@ -1494,6 +1496,7 @@ _readPlannedStmt(void) READ_NODE_FIELD(utilityStmt); READ_LOCATION_FIELD(stmt_location); READ_LOCATION_FIELD(stmt_len); + READ_OID_FIELD(query_owner_nspid); READ_DONE(); } diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 01335db511..2ae754fdb5 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -214,6 +214,7 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars, if (bms_is_subset(where_needed, rel->relids)) continue; + Assert(attno >= rel->min_attr && attno <= rel->max_attr); attno -= rel->min_attr; if (rel->attr_needed[attno] == NULL) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 96bf0601a8..750d4ea430 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -532,6 +532,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result->stmt_location = parse->stmt_location; result->stmt_len = parse->stmt_len; + result->query_owner_nspid = InvalidOid; + result->jitFlags = PGJIT_NONE; if (jit_enabled && jit_above_cost >= 0 && top_plan->total_cost > jit_above_cost) diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index a04ad6e99e..c9a6bd16b3 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -129,6 +129,7 @@ static Expr *simplify_function(Oid funcid, Oid result_type, int32 result_typmod, Oid result_collid, Oid input_collid, List **args_p, bool funcvariadic, bool process_args, bool allow_non_const, + bool funcprivate, Oid funcnspid, eval_const_expressions_context *context); static List *reorder_function_arguments(List *args, HeapTuple func_tuple); static List *add_function_defaults(List *args, HeapTuple func_tuple); @@ -138,11 +139,13 @@ static void recheck_cast_function_args(List *args, Oid result_type, static Expr *evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, Oid result_collid, Oid input_collid, List *args, bool funcvariadic, + bool funcprivate, Oid funcnspid, HeapTuple func_tuple, eval_const_expressions_context *context); static Expr *inline_function(Oid funcid, Oid result_type, Oid result_collid, Oid input_collid, List *args, bool funcvariadic, + bool funcprivate, Oid funcnspid, HeapTuple func_tuple, eval_const_expressions_context *context); static Node *substitute_actual_parameters(Node *expr, int nargs, List *args, @@ -2686,6 +2689,8 @@ eval_const_expressions_mutator(Node *node, expr->funcvariadic, true, true, + expr->funcprivate, + expr->funcnspid, context); if (simple) /* successfully simplified it */ return (Node *) simple; @@ -2705,6 +2710,8 @@ eval_const_expressions_mutator(Node *node, newexpr->funccollid = expr->funccollid; newexpr->inputcollid = expr->inputcollid; newexpr->args = args; + newexpr->funcprivate = expr->funcprivate; + newexpr->funcnspid = expr->funcnspid; newexpr->location = expr->location; return (Node *) newexpr; } @@ -2733,6 +2740,8 @@ eval_const_expressions_mutator(Node *node, false, true, true, + false, + InvalidOid, context); if (simple) /* successfully simplified it */ return (Node *) simple; @@ -2837,6 +2846,8 @@ eval_const_expressions_mutator(Node *node, false, false, false, + false, + InvalidOid, context); if (simple) /* successfully simplified it */ { @@ -3059,6 +3070,8 @@ eval_const_expressions_mutator(Node *node, false, true, true, + false, + InvalidOid, context); if (simple) /* successfully simplified output fn */ { @@ -3091,6 +3104,8 @@ eval_const_expressions_mutator(Node *node, false, false, true, + false, + InvalidOid, context); if (simple) /* successfully simplified input fn */ return (Node *) simple; @@ -4023,6 +4038,7 @@ static Expr * simplify_function(Oid funcid, Oid result_type, int32 result_typmod, Oid result_collid, Oid input_collid, List **args_p, bool funcvariadic, bool process_args, bool allow_non_const, + bool funcprivate, Oid funcnspid, eval_const_expressions_context *context) { List *args = *args_p; @@ -4068,6 +4084,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, newexpr = evaluate_function(funcid, result_type, result_typmod, result_collid, input_collid, args, funcvariadic, + funcprivate, funcnspid, func_tuple, context); if (!newexpr && allow_non_const && OidIsValid(func_form->protransform)) @@ -4088,6 +4105,8 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, fexpr.funccollid = result_collid; fexpr.inputcollid = input_collid; fexpr.args = args; + fexpr.funcprivate = funcprivate; + fexpr.funcnspid = funcnspid; fexpr.location = -1; newexpr = (Expr *) @@ -4098,6 +4117,7 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, if (!newexpr && allow_non_const) newexpr = inline_function(funcid, result_type, result_collid, input_collid, args, funcvariadic, + funcprivate, funcnspid, func_tuple, context); ReleaseSysCache(func_tuple); @@ -4337,6 +4357,7 @@ static Expr * evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, Oid result_collid, Oid input_collid, List *args, bool funcvariadic, + bool funcprivate, Oid funcnspid, HeapTuple func_tuple, eval_const_expressions_context *context) { @@ -4423,6 +4444,8 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, newexpr->funccollid = result_collid; /* doesn't matter */ newexpr->inputcollid = input_collid; newexpr->args = args; + newexpr->funcprivate = funcprivate; + newexpr->funcnspid = funcnspid; newexpr->location = -1; return evaluate_expr((Expr *) newexpr, result_type, result_typmod, @@ -4464,6 +4487,7 @@ static Expr * inline_function(Oid funcid, Oid result_type, Oid result_collid, Oid input_collid, List *args, bool funcvariadic, + bool funcprivate, Oid funcnspid, HeapTuple func_tuple, eval_const_expressions_context *context) { @@ -4556,6 +4580,8 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, fexpr->funccollid = result_collid; /* doesn't matter */ fexpr->inputcollid = input_collid; fexpr->args = args; + fexpr->funcprivate = funcprivate; + fexpr->funcnspid = funcnspid; fexpr->location = -1; pinfo = prepare_sql_fn_parse_info(func_tuple, diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 87f5e95827..13a87b33a4 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -664,7 +664,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); PARALLEL PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POLICY POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY - PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION + PRIOR PRIVATE PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION QUOTE @@ -7936,6 +7936,11 @@ common_func_opt_item: { $$ = makeDefElem("parallel", (Node *)makeString($2), @1); } + | PRIVATE + { + /* This function can be called only from routines */ + $$ = makeDefElem("scope", (Node *)makeString("private"), @1); + } ; createfunc_opt_item: @@ -15181,6 +15186,7 @@ unreserved_keyword: | PREPARED | PRESERVE | PRIOR + | PRIVATE | PRIVILEGES | PROCEDURAL | PROCEDURE diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 44257154b8..83aa22b053 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -102,6 +102,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, bool retset; int nvargs; Oid vatype; + bool funcprivate; + Oid funcnspid; FuncDetailCode fdresult; char aggkind = 0; ParseCallbackState pcbstate; @@ -259,7 +261,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, !func_variadic, true, &funcid, &rettype, &retset, &nvargs, &vatype, - &declared_arg_types, &argdefaults); + &declared_arg_types, &argdefaults, + &funcprivate, &funcnspid); cancel_parser_errposition_callback(&pcbstate); @@ -739,6 +742,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, funcexpr->funcformat = COERCE_EXPLICIT_CALL; /* funccollid and inputcollid will be set by parse_collate.c */ funcexpr->args = fargs; + funcexpr->funcprivate = funcprivate; + funcexpr->funcnspid = funcnspid; funcexpr->location = location; retval = (Node *) funcexpr; @@ -1386,7 +1391,9 @@ func_get_detail(List *funcname, int *nvargs, /* return value */ Oid *vatype, /* return value */ Oid **true_typeids, /* return value */ - List **argdefaults) /* optional return value */ + List **argdefaults, /* optional return value */ + bool *isprivate, /* return value */ + Oid *namespace) /* return value */ { FuncCandidateList raw_candidates; FuncCandidateList best_candidate; @@ -1610,6 +1617,10 @@ func_get_detail(List *funcname, *rettype = pform->prorettype; *retset = pform->proretset; *vatype = pform->provariadic; + + *isprivate = pform->proisprivate; + *namespace = pform->pronamespace; + /* fetch default args if caller wants 'em */ if (argdefaults && best_candidate->ndargs > 0) { diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 03e9a28a63..f51693d7af 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -2588,6 +2588,9 @@ pg_get_functiondef(PG_FUNCTION_ARGS) if (proc->proleakproof) appendStringInfoString(&buf, " LEAKPROOF"); + if (proc->proisprivate) + appendStringInfoString(&buf, " PRIVATE"); + /* This code for the default cost and rows should match functioncmds.c */ if (proc->prolang == INTERNALlanguageId || proc->prolang == ClanguageId) @@ -10765,6 +10768,8 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, Oid p_vatype; Oid *p_true_typeids; bool force_qualify = false; + bool p_isprivate; + Oid p_nspid; proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(proctup)) @@ -10818,7 +10823,8 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, !use_variadic, true, &p_funcid, &p_rettype, &p_retset, &p_nvargs, &p_vatype, - &p_true_typeids, NULL); + &p_true_typeids, NULL, + &p_isprivate, &p_nspid); else { p_result = FUNCDETAIL_NOTFOUND; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 9baf7b2fde..63752d8fca 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -11532,6 +11532,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) char *procost; char *prorows; char *proparallel; + char *proisprivate; char *lanname; char *rettypename; int nallargs; @@ -11553,6 +11554,26 @@ dumpFunc(Archive *fout, FuncInfo *finfo) asPart = createPQExpBuffer(); /* Fetch function-specific details */ + if (fout->remoteVersion > 110000) + { + /* + * proisprivate was added in 12 + */ + appendPQExpBuffer(query, + "SELECT proretset, prosrc, probin, " + "pg_catalog.pg_get_function_arguments(oid) AS funcargs, " + "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, " + "pg_catalog.pg_get_function_result(oid) AS funcresult, " + "array_to_string(protrftypes, ' ') AS protrftypes, " + "prokind, provolatile, proisstrict, prosecdef, " + "proleakproof, proconfig, procost, prorows, " + "proparallel, " + "proisprivate, " + "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname " + "FROM pg_catalog.pg_proc " + "WHERE oid = '%u'::pg_catalog.oid", + finfo->dobj.catId.oid); + } if (fout->remoteVersion >= 110000) { /* @@ -11731,6 +11752,11 @@ dumpFunc(Archive *fout, FuncInfo *finfo) else proparallel = NULL; + if (PQfnumber(res, "proisprivate") != -1) + proisprivate = PQgetvalue(res, 0, PQfnumber(res, "proisprivate")); + else + proisprivate = NULL; + lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname")); /* @@ -11914,6 +11940,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) if (proleakproof[0] == 't') appendPQExpBufferStr(q, " LEAKPROOF"); + + /* * COST and ROWS are emitted only if present and not default, so as not to * break backwards-compatibility of the dump without need. Keep this code @@ -11949,6 +11977,9 @@ dumpFunc(Archive *fout, FuncInfo *finfo) finfo->dobj.name); } + if (proisprivate && proisprivate[0] == 't') + appendPQExpBuffer(q, " PRIVATE"); + for (i = 0; i < nconfigitems; i++) { /* we feel free to scribble on configitems[] here */ diff --git a/src/include/catalog/pg_class.dat b/src/include/catalog/pg_class.dat index 9fffdef379..48ab7b2ec8 100644 --- a/src/include/catalog/pg_class.dat +++ b/src/include/catalog/pg_class.dat @@ -47,7 +47,7 @@ reloftype => '0', relowner => 'PGUID', relam => '0', relfilenode => '0', reltablespace => '0', relpages => '0', reltuples => '0', relallvisible => '0', reltoastrelid => '0', relhasindex => 'f', relisshared => 'f', - relpersistence => 'p', relkind => 'r', relnatts => '28', relchecks => '0', + relpersistence => 'p', relkind => 'r', relnatts => '29', relchecks => '0', relhasoids => 't', relhasrules => 'f', relhastriggers => 'f', relhassubclass => 'f', relrowsecurity => 'f', relforcerowsecurity => 'f', relispopulated => 't', relreplident => 'n', relispartition => 'f', diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index a34b2596fa..0b929a7365 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -75,6 +75,9 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce /* see PROPARALLEL_ categories below */ char proparallel BKI_DEFAULT(s); + /* is it a private function? */ + bool proisprivate BKI_DEFAULT(f); + /* number of arguments */ /* Note: need not be given in pg_proc.dat; genbki.pl will compute it */ int16 pronargs; @@ -192,6 +195,7 @@ extern ObjectAddress ProcedureCreate(const char *procedureName, bool isStrict, char volatility, char parallel, + bool isPrivate, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h index 10e9ded246..472ac5dce0 100644 --- a/src/include/executor/execdesc.h +++ b/src/include/executor/execdesc.h @@ -42,6 +42,7 @@ typedef struct QueryDesc ParamListInfo params; /* param values being passed in */ QueryEnvironment *queryEnv; /* query environment passed in */ int instrument_options; /* OR of InstrumentOption flags */ + Oid query_owner_nspid; /* the query is evaluated from object assigned to schema */ /* These fields are set by ExecutorStart */ TupleDesc tupDesc; /* descriptor for result tuples */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index f82b51667f..ce1f5349d7 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -242,7 +242,7 @@ ExecProcNode(PlanState *node) * prototypes from functions in execExpr.c */ extern ExprState *ExecInitExpr(Expr *node, PlanState *parent); -extern ExprState *ExecInitExprWithParams(Expr *node, ParamListInfo ext_params); +extern ExprState *ExecInitExprWithParams(Expr *node, ParamListInfo ext_params, Oid query_owner_nspid); extern ExprState *ExecInitQual(List *qual, PlanState *parent); extern ExprState *ExecInitCheck(List *qual, PlanState *parent); extern List *ExecInitExprList(List *nodes, PlanState *parent); diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 143a89a16c..df9037aa51 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -167,4 +167,6 @@ extern void SPICleanup(void); extern void AtEOXact_SPI(bool isCommit); extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid); +extern void assign_query_owner_nspid(SPIPlanPtr plan, Oid query_owner_nspid); + #endif /* SPI_H */ diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h index 401fd998f7..d6d88ab5a5 100644 --- a/src/include/executor/spi_priv.h +++ b/src/include/executor/spi_priv.h @@ -96,6 +96,7 @@ typedef struct _SPI_plan Oid *argtypes; /* Argument types (NULL if nargs is 0) */ ParserSetupHook parserSetup; /* alternative parameter spec method */ void *parserSetupArg; + Oid query_owner_nspid; } _SPI_plan; #endif /* SPI_PRIV_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 41fa2052a2..169bea82af 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -108,6 +108,8 @@ typedef struct ExprState Datum *innermost_domainval; bool *innermost_domainnull; + + Oid query_owner_nspid; } ExprState; @@ -253,6 +255,9 @@ typedef struct ExprContext /* Link to containing EState (NULL if a standalone ExprContext) */ struct EState *ecxt_estate; + /* Oid of namespace of object owning this query */ + Oid ecxt_query_owner_nspid; + /* Functions to call back when ExprContext is shut down or rescanned */ ExprContext_CB *ecxt_callbacks; } ExprContext; @@ -564,6 +569,8 @@ typedef struct EState /* The per-query shared memory area to use for parallel execution. */ struct dsa_area *es_query_dsa; + Oid es_query_owner_nspid; + /* * JIT information. es_jit_flags indicates whether JIT should be performed * and with which options. es_jit is created on-demand when JITing is diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 7c2abbd03a..94e29a857e 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -99,6 +99,8 @@ typedef struct PlannedStmt /* statement location in source string (copied from Query) */ int stmt_location; /* start location, or -1 if unknown */ int stmt_len; /* length in bytes; 0 means "rest of string" */ + + Oid query_owner_nspid; } PlannedStmt; /* macro for fetching the Plan associated with a SubPlan node */ diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 1b4b0d75af..0ddcd59e88 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -456,6 +456,8 @@ typedef struct FuncExpr Oid inputcollid; /* OID of collation that function should use */ List *args; /* arguments to the function */ int location; /* token location, or -1 if unknown */ + bool funcprivate; /* true if function is private */ + Oid funcnspid; /* OID of function namespace */ } FuncExpr; /* diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 23db40147b..576f211adf 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -311,6 +311,7 @@ PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD) PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD) PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD) PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD) +PG_KEYWORD("private", PRIVATE, UNRESERVED_KEYWORD) PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD) PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD) PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD) diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h index 11f9046e38..ae6cdc8f7a 100644 --- a/src/include/parser/parse_func.h +++ b/src/include/parser/parse_func.h @@ -41,7 +41,8 @@ extern FuncDetailCode func_get_detail(List *funcname, bool expand_variadic, bool expand_defaults, Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid *vatype, - Oid **true_typeids, List **argdefaults); + Oid **true_typeids, List **argdefaults, + bool *isprivate, Oid *namespace); extern int func_match_argtypes(int nargs, Oid *input_typeids, diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 721234d6d2..a35c61ec58 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -367,6 +367,7 @@ do_compile(FunctionCallInfo fcinfo, function->fn_is_trigger = PLPGSQL_NOT_TRIGGER; function->fn_prokind = procStruct->prokind; + function->fn_namespace = procStruct->pronamespace; /* * Initialize the compiler, particularly the namespace stack. The diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 380d1de8f4..22efcbe80c 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3989,6 +3989,9 @@ exec_prepare_plan(PLpgSQL_execstate *estate, if (plan == NULL) elog(ERROR, "SPI_prepare_params failed for \"%s\": %s", expr->query, SPI_result_code_string(SPI_result)); + + assign_query_owner_nspid(plan, estate->func->fn_namespace); + if (keepplan) SPI_keepplan(plan); expr->plan = plan; @@ -6060,6 +6063,9 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, econtext->ecxt_param_list_info = setup_param_list(estate, expr); + /* Setup query owner nspid - used for check of usage of private functions */ + econtext->ecxt_query_owner_nspid = estate->func->fn_namespace; + /* * Prepare the expression for execution, if it's not been done already in * the current transaction. (This will be forced to happen if we called @@ -6070,7 +6076,8 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt); expr->expr_simple_state = ExecInitExprWithParams(expr->expr_simple_expr, - econtext->ecxt_param_list_info); + econtext->ecxt_param_list_info, + estate->func->fn_namespace); expr->expr_simple_in_use = false; expr->expr_simple_lxid = curlxid; MemoryContextSwitchTo(oldcontext); diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 4a4c7cbd36..a141a7e217 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -928,6 +928,7 @@ typedef struct PLpgSQL_function { char *fn_signature; Oid fn_oid; + Oid fn_namespace; TransactionId fn_xmin; ItemPointerData fn_tid; PLpgSQL_trigtype fn_is_trigger;