📄 parse_func.c
字号:
* is returned to the caller, reflecting the structure of the * inheritance tree above the supplied arguments. * * The order of this vector is as follows: all superclasses of the * rightmost complex class are explored first. The exploration * continues from right to left. This policy means that we favor * keeping the leftmost argument type as low in the inheritance tree * as possible. This is intentional; it is exactly what we need to * do for method dispatch. The last type array we return is all * zeroes. This will match any functions for which return types are * not defined. There are lots of these (mostly builtins) in the * catalogs. */static Oid **argtype_inherit(int nargs, Oid *oid_array){ Oid relid; int i; InhPaths arginh[MAXFARGS]; for (i = 0; i < MAXFARGS; i++) { if (i < nargs) { arginh[i].self = oid_array[i]; if ((relid = typeidTypeRelid(oid_array[i])) != InvalidOid) arginh[i].nsupers = find_inheritors(relid, &(arginh[i].supervec)); else { arginh[i].nsupers = 0; arginh[i].supervec = (Oid *) NULL; } } else { arginh[i].self = InvalidOid; arginh[i].nsupers = 0; arginh[i].supervec = (Oid *) NULL; } } /* return an ordered cross-product of the classes involved */ return gen_cross_product(arginh, nargs);}static intfind_inheritors(Oid relid, Oid **supervec){ Oid *relidvec; Relation inhrel; HeapScanDesc inhscan; ScanKeyData skey; HeapTuple inhtup; TupleDesc inhtupdesc; int nvisited; SuperQE *qentry, *vnode; Dllist *visited, *queue; Dlelem *qe, *elt; Relation rd; Datum d; bool newrelid; char isNull; nvisited = 0; queue = DLNewList(); visited = DLNewList(); inhrel = heap_openr(InheritsRelationName); inhtupdesc = RelationGetDescr(inhrel); /* * Use queue to do a breadth-first traversal of the inheritance graph * from the relid supplied up to the root. */ do { ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel, F_OIDEQ, ObjectIdGetDatum(relid)); inhscan = heap_beginscan(inhrel, 0, SnapshotNow, 1, &skey); while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0))) { qentry = (SuperQE *) palloc(sizeof(SuperQE)); d = fastgetattr(inhtup, Anum_pg_inherits_inhparent, inhtupdesc, &isNull); qentry->sqe_relid = DatumGetObjectId(d); /* put this one on the queue */ DLAddTail(queue, DLNewElem(qentry)); } heap_endscan(inhscan); /* pull next unvisited relid off the queue */ do { qe = DLRemHead(queue); qentry = qe ? (SuperQE *) DLE_VAL(qe) : NULL; if (qentry == (SuperQE *) NULL) break; relid = qentry->sqe_relid; newrelid = true; for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) { vnode = (SuperQE *) DLE_VAL(elt); if (vnode && (qentry->sqe_relid == vnode->sqe_relid)) { newrelid = false; break; } } } while (!newrelid); if (qentry != (SuperQE *) NULL) { /* save the type id, rather than the relation id */ if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL) elog(ERROR, "Relid %u does not exist", qentry->sqe_relid); qentry->sqe_relid = typeTypeId(typenameType(RelationGetRelationName(rd)->data)); heap_close(rd); DLAddTail(visited, qe); nvisited++; } } while (qentry != (SuperQE *) NULL); heap_close(inhrel); if (nvisited > 0) { relidvec = (Oid *) palloc(nvisited * sizeof(Oid)); *supervec = relidvec; for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) { vnode = (SuperQE *) DLE_VAL(elt); *relidvec++ = vnode->sqe_relid; } } else *supervec = (Oid *) NULL; return nvisited;}static Oid **gen_cross_product(InhPaths *arginh, int nargs){ int nanswers; Oid **result, **iter; Oid *oneres; int i, j; int cur[MAXFARGS]; nanswers = 1; for (i = 0; i < nargs; i++) { nanswers *= (arginh[i].nsupers + 2); cur[i] = 0; } iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers); /* compute the cross product from right to left */ for (;;) { oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid)); MemSet(oneres, 0, MAXFARGS * sizeof(Oid)); for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--) continue; /* if we're done, terminate with NULL pointer */ if (i < 0) { *iter = NULL; return result; } /* no, increment this column and zero the ones after it */ cur[i] = cur[i] + 1; for (j = nargs - 1; j > i; j--) cur[j] = 0; for (i = 0; i < nargs; i++) { if (cur[i] == 0) oneres[i] = arginh[i].self; else if (cur[i] > arginh[i].nsupers) oneres[i] = 0; /* wild card */ else oneres[i] = arginh[i].supervec[cur[i] - 1]; } *iter++ = oneres; }}/* make_arguments() * Given the number and types of arguments to a function, and the * actual arguments and argument types, do the necessary typecasting. * * There are two ways an input typeid can differ from a function typeid: * 1) the input type inherits the function type, so no typecasting required * 2) the input type can be typecast into the function type * Right now, we only typecast unknowns, and that is all we check for. * * func_get_detail() now can find coersions for function arguments which * will make this function executable. So, we need to recover these * results here too. * - thomas 1998-03-25 */static voidmake_arguments(ParseState *pstate, int nargs, List *fargs, Oid *input_typeids, Oid *function_typeids){ List *current_fargs; int i; for (i = 0, current_fargs = fargs; i < nargs; i++, current_fargs = lnext(current_fargs)) { /* * unspecified type for string constant? then use heuristics for * conversion... */ if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid) { lfirst(current_fargs) = parser_typecast2(lfirst(current_fargs), input_typeids[i], typeidType(function_typeids[i]), -1); } /* types don't match? then force coersion using a function call... */ else if (input_typeids[i] != function_typeids[i]) { lfirst(current_fargs) = coerce_type(pstate, lfirst(current_fargs), input_typeids[i], function_typeids[i], -1); } }}/* ** setup_tlist ** Build a tlist that says which attribute to project to. ** This routine is called by ParseFuncOrColumn() to set up a target list ** on a tuple parameter or return value. Due to a bug in 4.0, ** it's not possible to refer to system attributes in this case. */static List *setup_tlist(char *attname, Oid relid){ TargetEntry *tle; Resdom *resnode; Var *varnode; Oid typeid; int32 type_mod; int attno; attno = get_attnum(relid, attname); if (attno < 0) elog(ERROR, "Cannot reference attribute '%s'" " of tuple params/return values for functions", attname); typeid = get_atttype(relid, attno); type_mod = get_atttypmod(relid, attno); resnode = makeResdom(1, typeid, type_mod, get_attname(relid, attno), 0, InvalidOid, false); varnode = makeVar(-1, attno, typeid, type_mod, 0, -1, attno); tle = makeTargetEntry(resnode, (Node *) varnode); return lcons(tle, NIL);}/* ** setup_base_tlist ** Build a tlist that extracts a base type from the tuple ** returned by the executor. */static List *setup_base_tlist(Oid typeid){ TargetEntry *tle; Resdom *resnode; Var *varnode; resnode = makeResdom(1, typeid, -1, "<noname>", 0, InvalidOid, false); varnode = makeVar(-1, 1, typeid, -1, 0, -1, 1); tle = makeTargetEntry(resnode, (Node *) varnode); return lcons(tle, NIL);}/* * ParseComplexProjection - * handles function calls with a single argument that is of complex type. * This routine returns NULL if it can't handle the projection (eg. sets). */static Node *ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg, bool *attisset){ Oid argtype; Oid argrelid; Relation rd; Oid relid; int attnum; switch (nodeTag(first_arg)) { case T_Iter: { Func *func; Iter *iter; iter = (Iter *) first_arg; func = (Func *) ((Expr *) iter->iterexpr)->oper; argtype = funcid_get_rettype(func->funcid); argrelid = typeidTypeRelid(argtype); if (argrelid && ((attnum = get_attnum(argrelid, funcname)) != InvalidAttrNumber)) { /* * the argument is a function returning a tuple, so * funcname may be a projection */ /* add a tlist to the func node and return the Iter */ rd = heap_openr(typeidTypeName(argtype)); if (RelationIsValid(rd)) { relid = RelationGetRelid(rd); heap_close(rd); } if (RelationIsValid(rd)) { func->func_tlist = setup_tlist(funcname, argrelid); iter->itertype = attnumTypeId(rd, attnum); return (Node *) iter; } else { elog(ERROR, "Function '%s' has bad return type %d", funcname, argtype); } } else { /* drop through */ ; } break; } case T_Var: { /* * The argument is a set, so this is either a projection * or a function call on this set. */ *attisset = true; break; } case T_Expr: { Expr *expr = (Expr *) first_arg; Func *funcnode; if (expr->opType != FUNC_EXPR) break; funcnode = (Func *) expr->oper; argtype = funcid_get_rettype(funcnode->funcid); argrelid = typeidTypeRelid(argtype); /* * the argument is a function returning a tuple, so * funcname may be a projection */ if (argrelid && (attnum = get_attnum(argrelid, funcname)) != InvalidAttrNumber) { /* add a tlist to the func node */ rd = heap_openr(typeidTypeName(argtype)); if (RelationIsValid(rd)) { relid = RelationGetRelid(rd); heap_close(rd); } if (RelationIsValid(rd)) { Expr *newexpr; funcnode->func_tlist = setup_tlist(funcname, argrelid); funcnode->functype = attnumTypeId(rd, attnum); newexpr = makeNode(Expr); newexpr->typeOid = funcnode->functype; newexpr->opType = FUNC_EXPR; newexpr->oper = (Node *) funcnode; newexpr->args = expr->args; return (Node *) newexpr; } } break; } case T_Param: { Param *param = (Param *) first_arg; /* * If the Param is a complex type, this could be a * projection */ rd = heap_openr(typeidTypeName(param->paramtype)); if (RelationIsValid(rd)) { relid = RelationGetRelid(rd); heap_close(rd); if ((attnum = get_attnum(relid, funcname)) != InvalidAttrNumber) { param->paramtype = attnumTypeId(rd, attnum); param->param_tlist = setup_tlist(funcname, relid); return (Node *) param; } } break; } default: break; } return NULL;}/* * Error message when function lookup fails that gives details of the * argument types */voidfunc_error(char *caller, char *funcname, int nargs, Oid *argtypes, char *msg){ char p[(NAMEDATALEN + 2) * MAXFMGRARGS], *ptr; int i; ptr = p; *ptr = '\0'; for (i = 0; i < nargs; i++) { if (i) { *ptr++ = ','; *ptr++ = ' '; } if (argtypes[i] != 0) { strcpy(ptr, typeidTypeName(argtypes[i])); *(ptr + NAMEDATALEN) = '\0'; } else strcpy(ptr, "opaque"); ptr += strlen(ptr); } if (caller == NULL) { elog(ERROR, "Function '%s(%s)' does not exist%s%s", funcname, p, ((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : "")); } else { elog(ERROR, "%s: function '%s(%s)' does not exist%s%s", caller, funcname, p, ((msg != NULL) ? "\n\t" : ""), ((msg != NULL) ? msg : "")); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -