📄 parse_func.c
字号:
{ bool result = false; Oid relid; Relation inhrel; List *visited, *queue; ListCell *queue_item; if (!ISCOMPLEX(subclassTypeId) || !ISCOMPLEX(superclassTypeId)) return false; relid = typeidTypeRelid(subclassTypeId); if (relid == InvalidOid) return false; /* * Begin the search at the relation itself, so add relid to the queue. */ queue = list_make1_oid(relid); visited = NIL; inhrel = heap_open(InheritsRelationId, AccessShareLock); /* * Use queue to do a breadth-first traversal of the inheritance graph from * the relid supplied up to the root. Notice that we append to the queue * inside the loop --- this is okay because the foreach() macro doesn't * advance queue_item until the next loop iteration begins. */ foreach(queue_item, queue) { Oid this_relid = lfirst_oid(queue_item); ScanKeyData skey; HeapScanDesc inhscan; HeapTuple inhtup; /* If we've seen this relid already, skip it */ if (list_member_oid(visited, this_relid)) continue; /* * Okay, this is a not-yet-seen relid. Add it to the list of * already-visited OIDs, then find all the types this relid inherits * from and add them to the queue. The one exception is we don't add * the original relation to 'visited'. */ if (queue_item != list_head(queue)) visited = lappend_oid(visited, this_relid); ScanKeyInit(&skey, Anum_pg_inherits_inhrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(this_relid)); inhscan = heap_beginscan(inhrel, SnapshotNow, 1, &skey); while ((inhtup = heap_getnext(inhscan, ForwardScanDirection)) != NULL) { Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup); Oid inhparent = inh->inhparent; /* If this is the target superclass, we're done */ if (get_rel_type_id(inhparent) == superclassTypeId) { result = true; break; } /* Else add to queue */ queue = lappend_oid(queue, inhparent); } heap_endscan(inhscan); if (result) break; } heap_close(inhrel, AccessShareLock); list_free(visited); list_free(queue); return result;}/* * make_fn_arguments() * * Given the actual argument expressions for a function, and the desired * input types for the function, add any necessary typecasting to the * expression tree. Caller should already have verified that casting is * allowed. * * Caution: given argument list is modified in-place. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */voidmake_fn_arguments(ParseState *pstate, List *fargs, Oid *actual_arg_types, Oid *declared_arg_types){ ListCell *current_fargs; int i = 0; foreach(current_fargs, fargs) { /* types don't match? then force coercion using a function call... */ if (actual_arg_types[i] != declared_arg_types[i]) { lfirst(current_fargs) = coerce_type(pstate, lfirst(current_fargs), actual_arg_types[i], declared_arg_types[i], -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); } i++; }}/* * ParseComplexProjection - * handles function calls with a single argument that is of complex type. * If the function call is actually a column projection, return a suitably * transformed expression tree. If not, return NULL. */static Node *ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg){ TupleDesc tupdesc; int i; /* * Special case for whole-row Vars so that we can resolve (foo.*).bar even * when foo is a reference to a subselect, join, or RECORD function. A * bonus is that we avoid generating an unnecessary FieldSelect; our * result can omit the whole-row Var and just be a Var for the selected * field. * * This case could be handled by expandRecordVariable, but it's more * efficient to do it this way when possible. */ if (IsA(first_arg, Var) && ((Var *) first_arg)->varattno == InvalidAttrNumber) { RangeTblEntry *rte; rte = GetRTEByRangeTablePosn(pstate, ((Var *) first_arg)->varno, ((Var *) first_arg)->varlevelsup); /* Return a Var if funcname matches a column, else NULL */ return scanRTEForColumn(pstate, rte, funcname); } /* * Else do it the hard way with get_expr_result_type(). * * If it's a Var of type RECORD, we have to work even harder: we have to * find what the Var refers to, and pass that to get_expr_result_type. * That task is handled by expandRecordVariable(). */ if (IsA(first_arg, Var) && ((Var *) first_arg)->vartype == RECORDOID) tupdesc = expandRecordVariable(pstate, (Var *) first_arg, 0); else if (get_expr_result_type(first_arg, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) return NULL; /* unresolvable RECORD type */ Assert(tupdesc); for (i = 0; i < tupdesc->natts; i++) { Form_pg_attribute att = tupdesc->attrs[i]; if (strcmp(funcname, NameStr(att->attname)) == 0 && !att->attisdropped) { /* Success, so generate a FieldSelect expression */ FieldSelect *fselect = makeNode(FieldSelect); fselect->arg = (Expr *) first_arg; fselect->fieldnum = i + 1; fselect->resulttype = att->atttypid; fselect->resulttypmod = att->atttypmod; return (Node *) fselect; } } return NULL; /* funcname does not match any column */}/* * helper routine for delivering "column does not exist" error message */static voidunknown_attribute(ParseState *pstate, Node *relref, char *attname){ RangeTblEntry *rte; if (IsA(relref, Var) && ((Var *) relref)->varattno == InvalidAttrNumber) { /* Reference the RTE by alias not by actual table name */ rte = GetRTEByRangeTablePosn(pstate, ((Var *) relref)->varno, ((Var *) relref)->varlevelsup); ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column %s.%s does not exist", rte->eref->aliasname, attname))); } else { /* Have to do it by reference to the type of the expression */ Oid relTypeId = exprType(relref); if (ISCOMPLEX(relTypeId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" not found in data type %s", attname, format_type_be(relTypeId)))); else if (relTypeId == RECORDOID) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("could not identify column \"%s\" in record data type", attname))); else ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("column notation .%s applied to type %s, " "which is not a composite type", attname, format_type_be(relTypeId)))); }}/* * funcname_signature_string * Build a string representing a function name, including arg types. * The result is something like "foo(integer)". * * This is typically used in the construction of function-not-found error * messages. */const char *funcname_signature_string(const char *funcname, int nargs, const Oid *argtypes){ StringInfoData argbuf; int i; initStringInfo(&argbuf); appendStringInfo(&argbuf, "%s(", funcname); for (i = 0; i < nargs; i++) { if (i) appendStringInfoString(&argbuf, ", "); appendStringInfoString(&argbuf, format_type_be(argtypes[i])); } appendStringInfoChar(&argbuf, ')'); return argbuf.data; /* return palloc'd string buffer */}/* * func_signature_string * As above, but function name is passed as a qualified name list. */const char *func_signature_string(List *funcname, int nargs, const Oid *argtypes){ return funcname_signature_string(NameListToString(funcname), nargs, argtypes);}/* * find_aggregate_func * Convenience routine to check that a function exists and is an * aggregate. * * Note: basetype is ANYOID if we are looking for an aggregate on * all types. */Oidfind_aggregate_func(List *aggname, Oid basetype, bool noError){ Oid oid; HeapTuple ftup; Form_pg_proc pform; oid = LookupFuncName(aggname, 1, &basetype, true); if (!OidIsValid(oid)) { if (noError) return InvalidOid; if (basetype == ANYOID) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("aggregate %s(*) does not exist", NameListToString(aggname)))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("aggregate %s(%s) does not exist", NameListToString(aggname), format_type_be(basetype)))); } /* Make sure it's an aggregate */ ftup = SearchSysCache(PROCOID, ObjectIdGetDatum(oid), 0, 0, 0); if (!HeapTupleIsValid(ftup)) /* should not happen */ elog(ERROR, "cache lookup failed for function %u", oid); pform = (Form_pg_proc) GETSTRUCT(ftup); if (!pform->proisagg) { ReleaseSysCache(ftup); if (noError) return InvalidOid; /* we do not use the (*) notation for functions... */ ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("function %s(%s) is not an aggregate", NameListToString(aggname), format_type_be(basetype)))); } ReleaseSysCache(ftup); return oid;}/* * LookupFuncName * Given a possibly-qualified function name and a set of argument types, * look up the function. * * If the function name is not schema-qualified, it is sought in the current * namespace search path. * * If the function is not found, we return InvalidOid if noError is true, * else raise an error. */OidLookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError){ FuncCandidateList clist; clist = FuncnameGetCandidates(funcname, nargs); while (clist) { if (memcmp(argtypes, clist->args, nargs * sizeof(Oid)) == 0) return clist->oid; clist = clist->next; } if (!noError) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(funcname, nargs, argtypes)))); return InvalidOid;}/* * LookupFuncNameTypeNames * Like LookupFuncName, but the argument types are specified by a * list of TypeName nodes. */OidLookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError){ Oid argoids[FUNC_MAX_ARGS]; int argcount; int i; ListCell *args_item; argcount = list_length(argtypes); if (argcount > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("functions cannot have more than %d arguments", FUNC_MAX_ARGS))); args_item = list_head(argtypes); for (i = 0; i < argcount; i++) { TypeName *t = (TypeName *) lfirst(args_item); argoids[i] = LookupTypeName(t); if (!OidIsValid(argoids[i])) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(t)))); args_item = lnext(args_item); } return LookupFuncName(funcname, argcount, argoids, noError);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -