pg_proc.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 739 行 · 第 1/2 页
C
739 行
errmsg("return type mismatch in function declared to return %s", format_type_be(rettype)), errdetail("Function's final statement must be a SELECT."))); return; } /* find the final query */ parse = (Query *) llast(queryTreeList); cmd = parse->commandType; tlist = parse->targetList; /* * The last query must be a SELECT if and only if return type isn't * VOID. */ if (rettype == VOIDOID) { if (cmd == CMD_SELECT) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", format_type_be(rettype)), errdetail("Function's final statement must not be a SELECT."))); return; } /* by here, the function is declared to return some type */ if (cmd != CMD_SELECT) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", format_type_be(rettype)), errdetail("Function's final statement must be a SELECT."))); /* * Count the non-junk entries in the result targetlist. */ tlistlen = ExecCleanTargetListLength(tlist); typerelid = typeidTypeRelid(rettype); if (fn_typtype == 'b' || fn_typtype == 'd') { /* Shouldn't have a typerelid */ Assert(typerelid == InvalidOid); /* * For base-type returns, the target list should have exactly one * entry, and its type should agree with what the user declared. * (As of Postgres 7.2, we accept binary-compatible types too.) */ if (tlistlen != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", format_type_be(rettype)), errdetail("Final SELECT must return exactly one column."))); restype = ((TargetEntry *) lfirst(tlist))->resdom->restype; if (!IsBinaryCoercible(restype, rettype)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", format_type_be(rettype)), errdetail("Actual return type is %s.", format_type_be(restype)))); } else if (fn_typtype == 'c') { /* Must have a typerelid */ Assert(typerelid != InvalidOid); /* * If the target list is of length 1, and the type of the varnode * in the target list matches the declared return type, this is * okay. This can happen, for example, where the body of the * function is 'SELECT func2()', where func2 has the same return * type as the function that's calling it. */ if (tlistlen == 1) { restype = ((TargetEntry *) lfirst(tlist))->resdom->restype; if (IsBinaryCoercible(restype, rettype)) return; } /* * Otherwise verify that the targetlist matches the return tuple * type. This part of the typechecking is a hack. We look up the * relation that is the declared return type, and scan the * non-deleted attributes to ensure that they match the datatypes * of the non-resjunk columns. */ reln = relation_open(typerelid, AccessShareLock); relnatts = reln->rd_rel->relnatts; rellogcols = 0; /* we'll count nondeleted cols as we go */ colindex = 0; foreach(tlistitem, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(tlistitem); Form_pg_attribute attr; Oid tletype; Oid atttype; if (tle->resdom->resjunk) continue; do { colindex++; if (colindex > relnatts) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", format_type_be(rettype)), errdetail("Final SELECT returns too many columns."))); attr = reln->rd_att->attrs[colindex - 1]; } while (attr->attisdropped); rellogcols++; tletype = exprType((Node *) tle->expr); atttype = attr->atttypid; if (!IsBinaryCoercible(tletype, atttype)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", format_type_be(rettype)), errdetail("Final SELECT returns %s instead of %s at column %d.", format_type_be(tletype), format_type_be(atttype), rellogcols))); } for (;;) { colindex++; if (colindex > relnatts) break; if (!reln->rd_att->attrs[colindex - 1]->attisdropped) rellogcols++; } if (tlistlen != rellogcols) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", format_type_be(rettype)), errdetail("Final SELECT returns too few columns."))); relation_close(reln, AccessShareLock); } else if (rettype == RECORDOID) { /* Shouldn't have a typerelid */ Assert(typerelid == InvalidOid); /* * For RECORD return type, defer this check until we get the first * tuple. */ } else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID) { /* This should already have been caught ... */ ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine result data type"), errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type."))); } else ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type %s is not supported for SQL functions", format_type_be(rettype))));}/* * Validator for internal functions * * Check that the given internal function name (the "prosrc" value) is * a known builtin function. */Datumfmgr_internal_validator(PG_FUNCTION_ARGS){ Oid funcoid = PG_GETARG_OID(0); HeapTuple tuple; Form_pg_proc proc; bool isnull; Datum tmp; char *prosrc; /* * We do not honor check_function_bodies since it's unlikely the * function name will be found later if it isn't there now. */ tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcoid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for function %u", funcoid); proc = (Form_pg_proc) GETSTRUCT(tuple); tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull); if (isnull) elog(ERROR, "null prosrc"); prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp)); if (fmgr_internal_function(prosrc) == InvalidOid) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("there is no built-in function named \"%s\"", prosrc))); ReleaseSysCache(tuple); PG_RETURN_VOID();}/* * Validator for C language functions * * Make sure that the library file exists, is loadable, and contains * the specified link symbol. Also check for a valid function * information record. */Datumfmgr_c_validator(PG_FUNCTION_ARGS){ Oid funcoid = PG_GETARG_OID(0); void *libraryhandle; HeapTuple tuple; Form_pg_proc proc; bool isnull; Datum tmp; char *prosrc; char *probin; /* * It'd be most consistent to skip the check if !check_function_bodies, * but the purpose of that switch is to be helpful for pg_dump loading, * and for pg_dump loading it's much better if we *do* check. */ tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcoid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for function %u", funcoid); proc = (Form_pg_proc) GETSTRUCT(tuple); tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull); if (isnull) elog(ERROR, "null prosrc"); prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp)); tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull); if (isnull) elog(ERROR, "null probin"); probin = DatumGetCString(DirectFunctionCall1(textout, tmp)); (void) load_external_function(probin, prosrc, true, &libraryhandle); (void) fetch_finfo_record(libraryhandle, prosrc); ReleaseSysCache(tuple); PG_RETURN_VOID();}/* * Validator for SQL language functions * * Parse it here in order to be sure that it contains no syntax errors. */Datumfmgr_sql_validator(PG_FUNCTION_ARGS){ Oid funcoid = PG_GETARG_OID(0); HeapTuple tuple; Form_pg_proc proc; List *querytree_list; bool isnull; Datum tmp; char *prosrc; char functyptype; bool haspolyarg; int i; tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcoid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for function %u", funcoid); proc = (Form_pg_proc) GETSTRUCT(tuple); functyptype = get_typtype(proc->prorettype); /* Disallow pseudotype result */ /* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */ if (functyptype == 'p' && proc->prorettype != RECORDOID && proc->prorettype != VOIDOID && proc->prorettype != ANYARRAYOID && proc->prorettype != ANYELEMENTOID) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SQL functions cannot return type %s", format_type_be(proc->prorettype)))); /* Disallow pseudotypes in arguments */ /* except for ANYARRAY or ANYELEMENT */ haspolyarg = false; for (i = 0; i < proc->pronargs; i++) { if (get_typtype(proc->proargtypes[i]) == 'p') { if (proc->proargtypes[i] == ANYARRAYOID || proc->proargtypes[i] == ANYELEMENTOID) haspolyarg = true; else ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SQL functions cannot have arguments of type %s", format_type_be(proc->proargtypes[i])))); } } /* Postpone body checks if !check_function_bodies */ if (check_function_bodies) { tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull); if (isnull) elog(ERROR, "null prosrc"); prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp)); /* * We can't do full prechecking of the function definition if there * are any polymorphic input types, because actual datatypes of * expression results will be unresolvable. The check will be done * at runtime instead. * * We can run the text through the raw parser though; this will at * least catch silly syntactic errors. */ if (!haspolyarg) { querytree_list = pg_parse_and_rewrite(prosrc, proc->proargtypes, proc->pronargs); check_sql_fn_retval(proc->prorettype, functyptype, querytree_list); } else querytree_list = pg_parse_query(prosrc); } ReleaseSysCache(tuple); PG_RETURN_VOID();}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?