parse_func.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,534 行 · 第 1/3 页
C
1,534 行
nvisited = 0; queue = NIL; visited = NIL; inhrel = heap_openr(InheritsRelationName, AccessShareLock); /* * Use queue to do a breadth-first traversal of the inheritance graph * from the relid supplied up to the root. At the top of the loop, * relid is the OID of the reltype to check next, queue is the list of * pending relids to check after this one, and visited is the list of * relids we need to output. */ do { /* find all types this relid inherits from, and add them to queue */ ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrelid, F_OIDEQ, ObjectIdGetDatum(relid)); inhscan = heap_beginscan(inhrel, SnapshotNow, 1, &skey); while ((inhtup = heap_getnext(inhscan, ForwardScanDirection)) != NULL) { Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup); queue = lappendo(queue, inh->inhparent); } heap_endscan(inhscan); /* pull next unvisited relid off the queue */ newrelid = false; while (queue != NIL) { relid = lfirsto(queue); queue = lnext(queue); if (!oidMember(relid, visited)) { newrelid = true; break; } } if (newrelid) { visited = lappendo(visited, relid); nvisited++; } } while (newrelid); heap_close(inhrel, AccessShareLock); if (nvisited > 0) { relidvec = (Oid *) palloc(nvisited * sizeof(Oid)); *supervec = relidvec; foreach(elt, visited) { /* return the type id, rather than the relation id */ *relidvec++ = get_rel_type_id(lfirsto(elt)); } } else *supervec = (Oid *) NULL; freeList(visited); /* * there doesn't seem to be any equally easy way to release the queue * list cells, but since they're palloc'd space it's not critical. */ return nvisited;}/* * Generate the ordered list of substitute argtype vectors to try. * * See comments for argtype_inherit. */static Oid **gen_cross_product(InhPaths *arginh, int nargs){ int nanswers; Oid **result; Oid *oneres; int i, j; int cur[FUNC_MAX_ARGS]; /* * At each position we want to try the original datatype, plus each * supertype. So the number of possible combinations is this: */ nanswers = 1; for (i = 0; i < nargs; i++) nanswers *= (arginh[i].nsupers + 1); /* * We also need an extra slot for the terminating NULL in the result * array, but that cancels out with the fact that we don't want to * generate the zero-changes case. So we need exactly nanswers slots. */ result = (Oid **) palloc(sizeof(Oid *) * nanswers); j = 0; /* * Compute the cross product from right to left. When cur[i] == 0, * generate the original input type at position i. When cur[i] == k * for k > 0, generate its k'th supertype. */ MemSet(cur, 0, sizeof(cur)); for (;;) { /* * Find a column we can increment. All the columns after it get * reset to zero. (Essentially, we're adding one to the multi- * digit number represented by cur[].) */ for (i = nargs - 1; i >= 0 && cur[i] >= arginh[i].nsupers; i--) cur[i] = 0; /* if none, we're done */ if (i < 0) break; /* increment this column */ cur[i] += 1; /* Generate the proper output type-OID vector */ oneres = (Oid *) palloc0(FUNC_MAX_ARGS * sizeof(Oid)); for (i = 0; i < nargs; i++) { if (cur[i] == 0) oneres[i] = arginh[i].self; else oneres[i] = arginh[i].supervec[cur[i] - 1]; } result[j++] = oneres; } /* terminate result vector with NULL pointer */ result[j++] = NULL; Assert(j == nanswers); return result;}/* * Given two type OIDs, determine whether the first is a complex type * (class type) that inherits from the second. */booltypeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId){ Oid relid; Oid *supervec; int nsupers, i; bool result; if (!ISCOMPLEX(subclassTypeId) || !ISCOMPLEX(superclassTypeId)) return false; relid = typeidTypeRelid(subclassTypeId); if (relid == InvalidOid) return false; nsupers = find_inheritors(relid, &supervec); result = false; for (i = 0; i < nsupers; i++) { if (supervec[i] == superclassTypeId) { result = true; break; } } if (supervec) pfree(supervec); 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){ List *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], COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); } i++; }}/* * setup_field_select * Build a FieldSelect node that says which attribute to project to. * This routine is called by ParseFuncOrColumn() when we have found * a projection on a function result or parameter. */static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid){ FieldSelect *fselect = makeNode(FieldSelect); AttrNumber attno; attno = get_attnum(relid, attname); if (attno == InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" of relation \"%s\" does not exist", attname, get_rel_name(relid)))); fselect->arg = (Expr *) input; fselect->fieldnum = attno; fselect->resulttype = get_atttype(relid, attno); fselect->resulttypmod = get_atttypmod(relid, attno); return fselect;}/* * 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. * * NB: argument is expected to be transformed already, ie, not a RangeVar. */static Node *ParseComplexProjection(char *funcname, Node *first_arg){ Oid argtype = exprType(first_arg); Oid argrelid; AttrNumber attnum; FieldSelect *fselect; argrelid = typeidTypeRelid(argtype); if (!argrelid) return NULL; /* probably should not happen */ attnum = get_attnum(argrelid, funcname); if (attnum == InvalidAttrNumber) return NULL; /* funcname does not match any column */ /* * Check for special cases where we don't want to return a * FieldSelect. */ switch (nodeTag(first_arg)) { case T_Var: { Var *var = (Var *) first_arg; /* * If the Var is a whole-row tuple, we can just replace it * with a simple Var reference. */ if (var->varattno == InvalidAttrNumber) { Oid vartype; int32 vartypmod; get_atttypetypmod(argrelid, attnum, &vartype, &vartypmod); return (Node *) makeVar(var->varno, attnum, vartype, vartypmod, var->varlevelsup); } break; } default: break; } /* Else generate a FieldSelect expression */ fselect = setup_field_select(first_arg, funcname, argrelid); return (Node *) fselect;}/* * Simple helper routine for delivering "column does not exist" error message */static voidunknown_attribute(const char *schemaname, const char *relname, const char *attname){ if (schemaname) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column %s.%s.%s does not exist", schemaname, relname, attname))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column %s.%s does not exist", relname, attname)));}/* * 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; MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid)); argcount = 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))); for (i = 0; i < argcount; i++) { TypeName *t = (TypeName *) lfirst(argtypes); argoids[i] = LookupTypeName(t); if (!OidIsValid(argoids[i])) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(t)))); argtypes = lnext(argtypes); } return LookupFuncName(funcname, argcount, argoids, noError);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?