/* * Return permissive policies to be added */ List * test_rls_hooks_permissive(CmdType cmdtype, Relation relation) { List *policies = NIL; RowSecurityPolicy *policy = palloc0(sizeof(RowSecurityPolicy)); Datum role; FuncCall *n; Node *e; ColumnRef *c; ParseState *qual_pstate; RangeTblEntry *rte; if (strcmp(RelationGetRelationName(relation), "rls_test_permissive") && strcmp(RelationGetRelationName(relation), "rls_test_both")) return NIL; qual_pstate = make_parsestate(NULL); rte = addRangeTableEntryForRelation(qual_pstate, relation, NULL, false, false); addRTEtoQuery(qual_pstate, rte, false, true, true); role = ObjectIdGetDatum(ACL_ID_PUBLIC); policy->policy_name = pstrdup("extension policy"); policy->policy_id = InvalidOid; policy->polcmd = '*'; policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true, 'i'); /* * policy->qual = (Expr *) makeConst(BOOLOID, -1, InvalidOid, * sizeof(bool), BoolGetDatum(true), false, true); */ n = makeFuncCall(list_make2(makeString("pg_catalog"), makeString("current_user")), NIL, 0); c = makeNode(ColumnRef); c->fields = list_make1(makeString("username")); c->location = 0; e = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", (Node *) n, (Node *) c, 0); policy->qual = (Expr *) transformWhereClause(qual_pstate, copyObject(e), EXPR_KIND_POLICY, "POLICY"); policy->with_check_qual = copyObject(policy->qual); policy->hassublinks = false; policies = list_make1(policy); return policies; }
/* * Interpret the function parameter list of a CREATE FUNCTION or * CREATE AGGREGATE statement. * * Input parameters: * parameters: list of FunctionParameter structs * languageOid: OID of function language (InvalidOid if it's CREATE AGGREGATE) * is_aggregate: needed only to determine error handling * queryString: likewise, needed only for error handling * * Results are stored into output parameters. parameterTypes must always * be created, but the other arrays are set to NULL if not needed. * variadicArgType is set to the variadic array type if there's a VARIADIC * parameter (there can be only one); or to InvalidOid if not. * requiredResultType is set to InvalidOid if there are no OUT parameters, * else it is set to the OID of the implied result type. */ void interpret_function_parameter_list(List *parameters, Oid languageOid, bool is_aggregate, const char *queryString, oidvector **parameterTypes, ArrayType **allParameterTypes, ArrayType **parameterModes, ArrayType **parameterNames, List **parameterDefaults, Oid *variadicArgType, Oid *requiredResultType) { int parameterCount = list_length(parameters); Oid *inTypes; int inCount = 0; Datum *allTypes; Datum *paramModes; Datum *paramNames; int outCount = 0; int varCount = 0; bool have_names = false; bool have_defaults = false; ListCell *x; int i; ParseState *pstate; *variadicArgType = InvalidOid; /* default result */ *requiredResultType = InvalidOid; /* default result */ inTypes = (Oid *) palloc(parameterCount * sizeof(Oid)); allTypes = (Datum *) palloc(parameterCount * sizeof(Datum)); paramModes = (Datum *) palloc(parameterCount * sizeof(Datum)); paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum)); *parameterDefaults = NIL; /* may need a pstate for parse analysis of default exprs */ pstate = make_parsestate(NULL); pstate->p_sourcetext = queryString; /* Scan the list and extract data into work arrays */ i = 0; foreach(x, parameters) { FunctionParameter *fp = (FunctionParameter *) lfirst(x); TypeName *t = fp->argType; bool isinput = false; Oid toid; Type typtup; AclResult aclresult; typtup = LookupTypeName(NULL, t, NULL, false); if (typtup) { if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) { /* As above, hard error if language is SQL */ if (languageOid == SQLlanguageId) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SQL function cannot accept shell type %s", TypeNameToString(t)))); /* We don't allow creating aggregates on shell types either */ else if (is_aggregate) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("aggregate cannot accept shell type %s", TypeNameToString(t)))); else ereport(NOTICE, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("argument type %s is only a shell", TypeNameToString(t)))); } toid = typeTypeId(typtup); ReleaseSysCache(typtup); } else { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type %s does not exist", TypeNameToString(t)))); toid = InvalidOid; /* keep compiler quiet */ } aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error_type(aclresult, toid); if (t->setof) { if (is_aggregate) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("aggregates cannot accept set arguments"))); else ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("functions cannot accept set arguments"))); } /* handle input parameters */ if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE) { /* other input parameters can't follow a VARIADIC parameter */ if (varCount > 0) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("VARIADIC parameter must be the last input parameter"))); inTypes[inCount++] = toid; isinput = true; } /* handle output parameters */ if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC) { if (outCount == 0) /* save first output param's type */ *requiredResultType = toid; outCount++; } if (fp->mode == FUNC_PARAM_VARIADIC) { *variadicArgType = toid; varCount++; /* validate variadic parameter type */ switch (toid) { case ANYARRAYOID: case ANYOID: /* okay */ break; default: if (!OidIsValid(get_element_type(toid))) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("VARIADIC parameter must be an array"))); break; } } allTypes[i] = ObjectIdGetDatum(toid); paramModes[i] = CharGetDatum(fp->mode); if (fp->name && fp->name[0]) { ListCell *px; /* * As of Postgres 9.0 we disallow using the same name for two * input or two output function parameters. Depending on the * function's language, conflicting input and output names might * be bad too, but we leave it to the PL to complain if so. */ foreach(px, parameters) { FunctionParameter *prevfp = (FunctionParameter *) lfirst(px); if (prevfp == fp) break; /* pure in doesn't conflict with pure out */ if ((fp->mode == FUNC_PARAM_IN || fp->mode == FUNC_PARAM_VARIADIC) && (prevfp->mode == FUNC_PARAM_OUT || prevfp->mode == FUNC_PARAM_TABLE)) continue; if ((prevfp->mode == FUNC_PARAM_IN || prevfp->mode == FUNC_PARAM_VARIADIC) && (fp->mode == FUNC_PARAM_OUT || fp->mode == FUNC_PARAM_TABLE)) continue; if (prevfp->name && prevfp->name[0] && strcmp(prevfp->name, fp->name) == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("parameter name \"%s\" used more than once", fp->name))); }
/* * GetStreamScanPlan */ ForeignScan * GetStreamScanPlan(PlannerInfo *root, RelOptInfo *baserel, Oid relid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan) { StreamFdwInfo *sinfo = (StreamFdwInfo *) baserel->fdw_private; List *physical_tlist = build_physical_tlist(root, baserel); RangeTblEntry *rte = NULL; int i; TableSampleClause *sample; Value *sample_cutoff = NULL; /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */ scan_clauses = extract_actual_clauses(scan_clauses, false); for (i = 1; i <= root->simple_rel_array_size; i++) { rte = root->simple_rte_array[i]; if (rte && rte->relid == relid) break; } if (!rte || rte->relid != relid) elog(ERROR, "stream RTE missing"); sample = rte->tablesample; if (sample) { double dcutoff; Datum d; ExprContext *econtext; bool isnull; Node *node; Expr *expr; ExprState *estate; ParseState *ps = make_parsestate(NULL); float4 percent; if (sample->tsmhandler != BERNOULLI_OID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("tablesample method %s is not supported by streams", get_func_name(sample->tsmhandler)), errhint("Only bernoulli tablesample method can be used with streams."))); if (sample->repeatable) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("streams don't support the REPEATABLE clause for tablesample"))); econtext = CreateStandaloneExprContext(); ps = make_parsestate(NULL); node = (Node *) linitial(sample->args); node = transformExpr(ps, node, EXPR_KIND_OTHER); expr = expression_planner((Expr *) node); estate = ExecInitExpr(expr, NULL); d = ExecEvalExpr(estate, econtext, &isnull, NULL); free_parsestate(ps); FreeExprContext(econtext, false); percent = DatumGetFloat4(d); if (percent < 0 || percent > 100 || isnan(percent)) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLESAMPLE_ARGUMENT), errmsg("sample percentage must be between 0 and 100"))); dcutoff = rint(((double) RAND_MAX + 1) * percent / 100); sample_cutoff = makeInteger((int) dcutoff); } return make_foreignscan(tlist, scan_clauses, baserel->relid, NIL, list_make3(sinfo->colnames, physical_tlist, sample_cutoff), NIL, NIL, outer_plan); }