📄 parse_func.c
字号:
} /* got it */ funcnode = makeNode(Func); funcnode->funcid = funcid; funcnode->functype = rettype; funcnode->funcisindex = false; funcnode->funcsize = 0; funcnode->func_fcache = NULL; funcnode->func_tlist = NIL; funcnode->func_planlist = NIL; /* perform the necessary typecasting */ make_arguments(pstate, nargs, fargs, oid_array, true_oid_array); /* * for functions returning base types, we want to project out the * return value. set up a target list to do that. the executor will * ignore these for c functions, and do the right thing for postquel * functions. */ if (typeidTypeRelid(rettype) == InvalidOid) funcnode->func_tlist = setup_base_tlist(rettype); /* * For sets, we want to make a targetlist to project out this * attribute of the set tuples. */ if (attisset) { if (!strcmp(funcname, "*")) funcnode->func_tlist = expandAll(pstate, relname, refname, curr_resno); else { funcnode->func_tlist = setup_tlist(funcname, argrelid); rettype = get_atttype(argrelid, get_attnum(argrelid, funcname)); } } /* * Sequence handling. */ if (funcid == F_NEXTVAL || funcid == F_CURRVAL || funcid == F_SETVAL) { Const *seq; char *seqrel; text *seqname; int32 aclcheck_result = -1; Assert(length(fargs) == ((funcid == F_SETVAL) ? 2 : 1)); seq = (Const *) lfirst(fargs); if (!IsA((Node *) seq, Const)) elog(ERROR, "Only constant sequence names are acceptable for function '%s'", funcname); seqrel = textout((text *) DatumGetPointer(seq->constvalue)); /* Do we have nextval('"Aa"')? */ if (strlen(seqrel) >= 2 && seqrel[0] == '\"' && seqrel[strlen(seqrel) - 1] == '\"') { /* strip off quotes, keep case */ seqrel = pstrdup(seqrel + 1); seqrel[strlen(seqrel) - 1] = '\0'; pfree(DatumGetPointer(seq->constvalue)); seq->constvalue = (Datum) textin(seqrel); } else { pfree(seqrel); seqname = lower((text *) DatumGetPointer(seq->constvalue)); pfree(DatumGetPointer(seq->constvalue)); seq->constvalue = PointerGetDatum(seqname); seqrel = textout(seqname); } if ((aclcheck_result = pg_aclcheck(seqrel, GetPgUserName(), (((funcid == F_NEXTVAL) || (funcid == F_SETVAL)) ? ACL_WR : ACL_RD))) != ACLCHECK_OK) elog(ERROR, "%s.%s: %s", seqrel, funcname, aclcheck_error_strings[aclcheck_result]); pfree(seqrel); if (funcid == F_NEXTVAL && pstate->p_in_where_clause) elog(ERROR, "Sequence function nextval is not allowed in WHERE clauses"); if (funcid == F_SETVAL && pstate->p_in_where_clause) elog(ERROR, "Sequence function setval is not allowed in WHERE clauses"); } expr = makeNode(Expr); expr->typeOid = rettype; expr->opType = FUNC_EXPR; expr->oper = (Node *) funcnode; expr->args = fargs; retval = (Node *) expr; /* * if the function returns a set of values, then we need to iterate * over all the returned values in the executor, so we stick an iter * node here. if it returns a singleton, then we don't need the iter * node. */ if (retset) { Iter *iter = makeNode(Iter); iter->itertype = rettype; iter->iterexpr = retval; retval = (Node *) iter; } return retval;}static Oidfuncid_get_rettype(Oid funcid){ HeapTuple func_tuple = NULL; Oid funcrettype = InvalidOid; func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0, 0, 0); if (!HeapTupleIsValid(func_tuple)) elog(ERROR, "Function OID %u does not exist", funcid); funcrettype = (Oid) ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype; return funcrettype;}/* func_get_candidates() * get a list of all argument type vectors for which a function named * funcname taking nargs arguments exists */static CandidateListfunc_get_candidates(char *funcname, int nargs){ Relation heapRelation; Relation idesc; ScanKeyData skey; HeapTupleData tuple; IndexScanDesc sd; RetrieveIndexResult indexRes; Form_pg_proc pgProcP; CandidateList candidates = NULL; CandidateList current_candidate; int i; heapRelation = heap_openr(ProcedureRelationName); ScanKeyEntryInitialize(&skey, (bits16) 0x0, (AttrNumber) 1, (RegProcedure) F_NAMEEQ, (Datum) funcname); idesc = index_openr(ProcedureNameIndex); sd = index_beginscan(idesc, false, 1, &skey); do { indexRes = index_getnext(sd, ForwardScanDirection); if (indexRes) { Buffer buffer; tuple.t_self = indexRes->heap_iptr; heap_fetch(heapRelation, SnapshotNow, &tuple, &buffer); pfree(indexRes); if (tuple.t_data != NULL) { pgProcP = (Form_pg_proc) GETSTRUCT(&tuple); if (pgProcP->pronargs == nargs) { current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); current_candidate->args = (Oid *) palloc(MAXFARGS * sizeof(Oid)); MemSet(current_candidate->args, 0, MAXFARGS * sizeof(Oid)); for (i = 0; i < nargs; i++) current_candidate->args[i] = pgProcP->proargtypes[i]; current_candidate->next = candidates; candidates = current_candidate; } ReleaseBuffer(buffer); } } } while (indexRes); index_endscan(sd); index_close(idesc); heap_close(heapRelation); return candidates;}/* match_argtypes() * Given a list of possible typeid arrays to a function and an array of * input typeids, produce a shortlist of those function typeid arrays * that match the input typeids (either exactly or by coercion), and * return the number of such arrays */static intmatch_argtypes(int nargs, Oid *input_typeids, CandidateList function_typeids, CandidateList *candidates) /* return value */{ CandidateList current_candidate; CandidateList matching_candidate; Oid *current_typeids; int ncandidates = 0; *candidates = NULL; for (current_candidate = function_typeids; current_candidate != NULL; current_candidate = current_candidate->next) { current_typeids = current_candidate->args; if (can_coerce_type(nargs, input_typeids, current_typeids)) { matching_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); matching_candidate->args = current_typeids; matching_candidate->next = *candidates; *candidates = matching_candidate; ncandidates++; } } return ncandidates;} /* match_argtypes() *//* func_select_candidate() * Given the input argtype array and more than one candidate * for the function argtype array, attempt to resolve the conflict. * returns the selected argtype array if the conflict can be resolved, * otherwise returns NULL. * * If all input Oids are UNKNOWNOID, then try matching with TEXTOID. * Otherwise, could return first function arguments on list of candidates. * But for now, return NULL and make the user give a better hint. * - thomas 1998-03-17 */static Oid *func_select_candidate(int nargs, Oid *input_typeids, CandidateList candidates){ CandidateList current_candidate; CandidateList last_candidate; Oid *current_typeids; int i; int ncandidates; int nbestMatch, nmatch, nident; CATEGORY slot_category, current_category; Oid slot_type, current_type;/* * Run through all candidates and keep those with the most matches * on explicit types. Keep all candidates if none match. */ ncandidates = 0; nbestMatch = 0; last_candidate = NULL; for (current_candidate = candidates; current_candidate != NULL; current_candidate = current_candidate->next) { current_typeids = current_candidate->args; nmatch = 0; nident = 0; for (i = 0; i < nargs; i++) { if ((input_typeids[i] != UNKNOWNOID) && (current_typeids[i] == input_typeids[i])) nmatch++; else if (IS_BINARY_COMPATIBLE(current_typeids[i], input_typeids[i])) nident++; } if ((nmatch + nident) == nargs) return current_candidate->args; if ((nmatch > nbestMatch) || (last_candidate == NULL)) { nbestMatch = nmatch; candidates = current_candidate; last_candidate = current_candidate; ncandidates = 1; } else if (nmatch == nbestMatch) { last_candidate->next = current_candidate; last_candidate = current_candidate; ncandidates++; } else last_candidate->next = NULL; } if (ncandidates == 1) return candidates->args;/* * Still too many candidates? * Try assigning types for the unknown columns. */ for (i = 0; i < nargs; i++) { if (input_typeids[i] == UNKNOWNOID) { slot_category = INVALID_TYPE; slot_type = InvalidOid; for (current_candidate = candidates; current_candidate != NULL; current_candidate = current_candidate->next) { current_typeids = current_candidate->args; current_type = current_typeids[i]; current_category = TypeCategory(current_typeids[i]); if (slot_category == InvalidOid) { slot_category = current_category; slot_type = current_type; } else if ((current_category != slot_category) && IS_BUILTIN_TYPE(current_type)) return NULL; else if (current_type != slot_type) { if (IsPreferredType(slot_category, current_type)) { slot_type = current_type; candidates = current_candidate; } else if (IsPreferredType(slot_category, slot_type)) candidates->next = current_candidate->next; } } if (slot_type != InvalidOid) input_typeids[i] = slot_type; } else { } } ncandidates = 0; for (current_candidate = candidates; current_candidate != NULL; current_candidate = current_candidate->next) ncandidates++; if (ncandidates == 1) return candidates->args; return NULL;} /* func_select_candidate() *//* func_get_detail() * Find the named function in the system catalogs. * * Attempt to find the named function in the system catalogs with * arguments exactly as specified, so that the normal case * (exact match) is as quick as possible. * * If an exact match isn't found: * 1) get a vector of all possible input arg type arrays constructed * from the superclasses of the original input arg types * 2) get a list of all possible argument type arrays to the function * with given name and number of arguments * 3) for each input arg type array from vector #1: * a) find how many of the function arg type arrays from list #2 * it can be coerced to * b) if the answer is one, we have our function * c) if the answer is more than one, attempt to resolve the conflict * d) if the answer is zero, try the next array from vector #1 */static boolfunc_get_detail(char *funcname, int nargs, Oid *oid_array, Oid *funcid, /* return value */ Oid *rettype, /* return value */ bool *retset, /* return value */ Oid **true_typeids) /* return value */{ Oid **input_typeid_vector; Oid *current_input_typeids; CandidateList function_typeids; CandidateList current_function_typeids; HeapTuple ftup; Form_pg_proc pform; /* attempt to find with arguments exactly as specified... */ ftup = SearchSysCacheTuple(PRONAME, PointerGetDatum(funcname), Int32GetDatum(nargs), PointerGetDatum(oid_array), 0); *true_typeids = oid_array; /* didn't find an exact match, so now try to match up candidates... */ if (!HeapTupleIsValid(ftup)) { function_typeids = func_get_candidates(funcname, nargs); /* found something, so let's look through them... */ if (function_typeids != NULL) { int ncandidates; input_typeid_vector = argtype_inherit(nargs, oid_array); current_input_typeids = oid_array; do { ncandidates = match_argtypes(nargs, current_input_typeids, function_typeids, ¤t_function_typeids); /* one match only? then run with it... */ if (ncandidates == 1) { *true_typeids = current_function_typeids->args; ftup = SearchSysCacheTuple(PRONAME, PointerGetDatum(funcname), Int32GetDatum(nargs), PointerGetDatum(*true_typeids), 0); Assert(HeapTupleIsValid(ftup)); } /* * multiple candidates? then better decide or throw an * error... */ else if (ncandidates > 1) { *true_typeids = func_select_candidate(nargs, current_input_typeids, current_function_typeids); /* couldn't decide, so quit */ if (*true_typeids == NULL) { func_error(NULL, funcname, nargs, oid_array, "Unable to identify a function which satisfies the given argument types" "\n\tYou will have to retype your query using explicit typecasts"); } /* found something, so use the first one... */ else { ftup = SearchSysCacheTuple(PRONAME, PointerGetDatum(funcname), Int32GetDatum(nargs), PointerGetDatum(*true_typeids), 0); Assert(HeapTupleIsValid(ftup)); } } current_input_typeids = *input_typeid_vector++; } while (current_input_typeids != InvalidOid && ncandidates == 0); } } if (!HeapTupleIsValid(ftup)) { Type tp; if (nargs == 1) { tp = typeidType(oid_array[0]); if (typeTypeFlag(tp) == 'c') elog(ERROR, "No such attribute or function '%s'", funcname); } } else { pform = (Form_pg_proc) GETSTRUCT(ftup); *funcid = ftup->t_data->t_oid; *rettype = pform->prorettype; *retset = pform->proretset; return true; } /* shouldn't reach here */ return false;} /* func_get_detail() *//* * argtype_inherit() -- Construct an argtype vector reflecting the * inheritance properties of the supplied argv. * * This function is used to disambiguate among functions with the * same name but different signatures. It takes an array of eight * type ids. For each type id in the array that's a complex type * (a class), it walks up the inheritance tree, finding all * superclasses of that type. A vector of new Oid type arrays
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -