📄 namespace.c
字号:
/* deconstruct the name list */ DeconstructQualifiedName(names, &schemaname, &funcname); if (schemaname) { /* use exact schema given */ namespaceId = LookupExplicitNamespace(schemaname); } else { /* flag to indicate we need namespace search */ namespaceId = InvalidOid; recomputeNamespacePath(); } /* Search syscache by name only */ catlist = SearchSysCacheList(PROCNAMEARGSNSP, 1, CStringGetDatum(funcname), 0, 0, 0); for (i = 0; i < catlist->n_members; i++) { HeapTuple proctup = &catlist->members[i]->tuple; Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); int pronargs = procform->pronargs; int pathpos = 0; FuncCandidateList newResult; /* Ignore if it doesn't match requested argument count */ if (nargs >= 0 && pronargs != nargs) continue; if (OidIsValid(namespaceId)) { /* Consider only procs in specified namespace */ if (procform->pronamespace != namespaceId) continue; /* No need to check args, they must all be different */ } else { /* Consider only procs that are in the search path */ ListCell *nsp; foreach(nsp, namespaceSearchPath) { if (procform->pronamespace == lfirst_oid(nsp)) break; pathpos++; } if (nsp == NULL) continue; /* proc is not in search path */ /* * Okay, it's in the search path, but does it have the same * arguments as something we already accepted? If so, keep only * the one that appears earlier in the search path. * * If we have an ordered list from SearchSysCacheList (the normal * case), then any conflicting proc must immediately adjoin this * one in the list, so we only need to look at the newest result * item. If we have an unordered list, we have to scan the whole * result list. */ if (resultList) { FuncCandidateList prevResult; if (catlist->ordered) { if (pronargs == resultList->nargs && memcmp(procform->proargtypes.values, resultList->args, pronargs * sizeof(Oid)) == 0) prevResult = resultList; else prevResult = NULL; } else { for (prevResult = resultList; prevResult; prevResult = prevResult->next) { if (pronargs == prevResult->nargs && memcmp(procform->proargtypes.values, prevResult->args, pronargs * sizeof(Oid)) == 0) break; } } if (prevResult) { /* We have a match with a previous result */ Assert(pathpos != prevResult->pathpos); if (pathpos > prevResult->pathpos) continue; /* keep previous result */ /* replace previous result */ prevResult->pathpos = pathpos; prevResult->oid = HeapTupleGetOid(proctup); continue; /* args are same, of course */ } } } /* * Okay to add it to result list */ newResult = (FuncCandidateList) palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid) + pronargs * sizeof(Oid)); newResult->pathpos = pathpos; newResult->oid = HeapTupleGetOid(proctup); newResult->nargs = pronargs; memcpy(newResult->args, procform->proargtypes.values, pronargs * sizeof(Oid)); newResult->next = resultList; resultList = newResult; } ReleaseSysCacheList(catlist); return resultList;}/* * FunctionIsVisible * Determine whether a function (identified by OID) is visible in the * current search path. Visible means "would be found by searching * for the unqualified function name with exact argument matches". */boolFunctionIsVisible(Oid funcid){ HeapTuple proctup; Form_pg_proc procform; Oid pronamespace; bool visible; proctup = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0); if (!HeapTupleIsValid(proctup)) elog(ERROR, "cache lookup failed for function %u", funcid); procform = (Form_pg_proc) GETSTRUCT(proctup); recomputeNamespacePath(); /* * Quick check: if it ain't in the path at all, it ain't visible. Items in * the system namespace are surely in the path and so we needn't even do * list_member_oid() for them. */ pronamespace = procform->pronamespace; if (pronamespace != PG_CATALOG_NAMESPACE && !list_member_oid(namespaceSearchPath, pronamespace)) visible = false; else { /* * If it is in the path, it might still not be visible; it could be * hidden by another proc of the same name and arguments earlier in * the path. So we must do a slow check to see if this is the same * proc that would be found by FuncnameGetCandidates. */ char *proname = NameStr(procform->proname); int nargs = procform->pronargs; FuncCandidateList clist; visible = false; clist = FuncnameGetCandidates(list_make1(makeString(proname)), nargs); for (; clist; clist = clist->next) { if (memcmp(clist->args, procform->proargtypes.values, nargs * sizeof(Oid)) == 0) { /* Found the expected entry; is it the right proc? */ visible = (clist->oid == funcid); break; } } } ReleaseSysCache(proctup); return visible;}/* * OpernameGetCandidates * Given a possibly-qualified operator name and operator kind, * retrieve a list of the possible matches. * * If oprkind is '\0', we return all operators matching the given name, * regardless of arguments. * * We search a single namespace if the operator name is qualified, else * all namespaces in the search path. The return list will never contain * multiple entries with identical argument lists --- in the multiple- * namespace case, we arrange for entries in earlier namespaces to mask * identical entries in later namespaces. * * The returned items always have two args[] entries --- one or the other * will be InvalidOid for a prefix or postfix oprkind. nargs is 2, too. */FuncCandidateListOpernameGetCandidates(List *names, char oprkind){ FuncCandidateList resultList = NULL; char *resultSpace = NULL; int nextResult = 0; char *schemaname; char *opername; Oid namespaceId; CatCList *catlist; int i; /* deconstruct the name list */ DeconstructQualifiedName(names, &schemaname, &opername); if (schemaname) { /* use exact schema given */ namespaceId = LookupExplicitNamespace(schemaname); } else { /* flag to indicate we need namespace search */ namespaceId = InvalidOid; recomputeNamespacePath(); } /* Search syscache by name only */ catlist = SearchSysCacheList(OPERNAMENSP, 1, CStringGetDatum(opername), 0, 0, 0); /* * In typical scenarios, most if not all of the operators found by the * catcache search will end up getting returned; and there can be quite a * few, for common operator names such as '=' or '+'. To reduce the time * spent in palloc, we allocate the result space as an array large enough * to hold all the operators. The original coding of this routine did a * separate palloc for each operator, but profiling revealed that the * pallocs used an unreasonably large fraction of parsing time. */#define SPACE_PER_OP MAXALIGN(sizeof(struct _FuncCandidateList) + sizeof(Oid)) if (catlist->n_members > 0) resultSpace = palloc(catlist->n_members * SPACE_PER_OP); for (i = 0; i < catlist->n_members; i++) { HeapTuple opertup = &catlist->members[i]->tuple; Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup); int pathpos = 0; FuncCandidateList newResult; /* Ignore operators of wrong kind, if specific kind requested */ if (oprkind && operform->oprkind != oprkind) continue; if (OidIsValid(namespaceId)) { /* Consider only opers in specified namespace */ if (operform->oprnamespace != namespaceId) continue; /* No need to check args, they must all be different */ } else { /* Consider only opers that are in the search path */ ListCell *nsp; foreach(nsp, namespaceSearchPath) { if (operform->oprnamespace == lfirst_oid(nsp)) break; pathpos++; } if (nsp == NULL) continue; /* oper is not in search path */ /* * Okay, it's in the search path, but does it have the same * arguments as something we already accepted? If so, keep only * the one that appears earlier in the search path. * * If we have an ordered list from SearchSysCacheList (the normal * case), then any conflicting oper must immediately adjoin this * one in the list, so we only need to look at the newest result * item. If we have an unordered list, we have to scan the whole * result list. */ if (resultList) { FuncCandidateList prevResult; if (catlist->ordered) { if (operform->oprleft == resultList->args[0] && operform->oprright == resultList->args[1]) prevResult = resultList; else prevResult = NULL; } else { for (prevResult = resultList; prevResult; prevResult = prevResult->next) { if (operform->oprleft == prevResult->args[0] && operform->oprright == prevResult->args[1]) break; } } if (prevResult) { /* We have a match with a previous result */ Assert(pathpos != prevResult->pathpos); if (pathpos > prevResult->pathpos) continue; /* keep previous result */ /* replace previous result */ prevResult->pathpos = pathpos; prevResult->oid = HeapTupleGetOid(opertup); continue; /* args are same, of course */ } } } /* * Okay to add it to result list */ newResult = (FuncCandidateList) (resultSpace + nextResult); nextResult += SPACE_PER_OP; newResult->pathpos = pathpos; newResult->oid = HeapTupleGetOid(opertup); newResult->nargs = 2; newResult->args[0] = operform->oprleft; newResult->args[1] = operform->oprright; newResult->next = resultList; resultList = newResult; } ReleaseSysCacheList(catlist); return resultList;}/* * OperatorIsVisible * Determine whether an operator (identified by OID) is visible in the * current search path. Visible means "would be found by searching * for the unqualified operator name with exact argument matches". */boolOperatorIsVisible(Oid oprid){ HeapTuple oprtup; Form_pg_operator oprform; Oid oprnamespace; bool visible; oprtup = SearchSysCache(OPEROID, ObjectIdGetDatum(oprid), 0, 0, 0); if (!HeapTupleIsValid(oprtup)) elog(ERROR, "cache lookup failed for operator %u", oprid); oprform = (Form_pg_operator) GETSTRUCT(oprtup); recomputeNamespacePath(); /* * Quick check: if it ain't in the path at all, it ain't visible. Items in * the system namespace are surely in the path and so we needn't even do * list_member_oid() for them. */ oprnamespace = oprform->oprnamespace; if (oprnamespace != PG_CATALOG_NAMESPACE && !list_member_oid(namespaceSearchPath, oprnamespace)) visible = false; else { /* * If it is in the path, it might still not be visible; it could be * hidden by another operator of the same name and arguments earlier * in the path. So we must do a slow check to see if this is the same * operator that would be found by OpernameGetCandidates. */ char *oprname = NameStr(oprform->oprname); FuncCandidateList clist; visible = false; clist = OpernameGetCandidates(list_make1(makeString(oprname)), oprform->oprkind); for (; clist; clist = clist->next) { if (clist->args[0] == oprform->oprleft && clist->args[1] == oprform->oprright) { /* Found the expected entry; is it the right op? */ visible = (clist->oid == oprid); break; } } } ReleaseSysCache(oprtup); return visible;}/* * OpclassnameGetOpcid * Try to resolve an unqualified index opclass name. * Returns OID if opclass found in search path, else InvalidOid. * * This is essentially the same as TypenameGetTypid, but we have to have * an extra argument for the index AM OID. */OidOpclassnameGetOpcid(Oid amid, const char *opcname){ Oid opcid; ListCell *l; recomputeNamespacePath(); foreach(l, namespaceSearchPath) { Oid namespaceId = lfirst_oid(l); opcid = GetSysCacheOid(CLAAMNAMENSP, ObjectIdGetDatum(amid), PointerGetDatum(opcname), ObjectIdGetDatum(namespaceId), 0); if (OidIsValid(opcid)) return opcid; } /* Not found in path */ return InvalidOid;}/* * OpclassIsVisible * Determine whether an opclass (identified by OID) is visible in the * current search path. Visible means "would be found by searching * for the unqualified opclass name". */boolOpclassIsVisible(Oid opcid){ HeapTuple opctup; Form_pg_opclass opcform; Oid opcnamespace; bool visible; opctup = SearchSysCache(CLAOID, ObjectIdGetDatum(opcid), 0, 0, 0); if (!HeapTupleIsValid(opctup)) elog(ERROR, "cache lookup failed for opclass %u", opcid); opcform = (Form_pg_opclass) GETSTRUCT(opctup); recomputeNamespacePath(); /* * Quick check: if it ain't in the path at all, it ain't visible. Items in * the system namespace are surely in the path and so we needn't even do * list_member_oid() for them. */ opcnamespace = opcform->opcnamespace; if (opcnamespace != PG_CATALOG_NAMESPACE && !list_member_oid(namespaceSearchPath, opcnamespace)) visible = false; else { /* * If it is in the path, it might still not be visible; it could be
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -