mirror of
https://github.com/postgres/postgres.git
synced 2025-06-06 00:02:36 -04:00
Harden xxx_is_visible() functions against concurrent object drops.
For the same reasons given in commit 403ac226d, adjust these functions to not assume that checking SearchSysCacheExists can guarantee success of a later fetch. This follows the same internal API choices made in the earlier commit: add a function XXXExt(oid, is_missing) and use that to eliminate the need for a separate existence check. The changes are very straightforward, though tedious. For the moment I just made the new functions static in namespace.c, but we could export them if a need emerges. Per bug #18014 from Alexander Lakhin. Given the lack of hard evidence that there's a bug in non-debug builds, I'm content to fix this only in HEAD. Discussion: https://postgr.es/m/18014-28c81cb79d44295d@postgresql.org
This commit is contained in:
parent
403ac226dd
commit
fcdd6689d0
@ -183,6 +183,19 @@ char *namespace_search_path = NULL;
|
|||||||
|
|
||||||
|
|
||||||
/* Local functions */
|
/* Local functions */
|
||||||
|
static bool RelationIsVisibleExt(Oid relid, bool *is_missing);
|
||||||
|
static bool TypeIsVisibleExt(Oid typid, bool *is_missing);
|
||||||
|
static bool FunctionIsVisibleExt(Oid funcid, bool *is_missing);
|
||||||
|
static bool OperatorIsVisibleExt(Oid oprid, bool *is_missing);
|
||||||
|
static bool OpclassIsVisibleExt(Oid opcid, bool *is_missing);
|
||||||
|
static bool OpfamilyIsVisibleExt(Oid opfid, bool *is_missing);
|
||||||
|
static bool CollationIsVisibleExt(Oid collid, bool *is_missing);
|
||||||
|
static bool ConversionIsVisibleExt(Oid conid, bool *is_missing);
|
||||||
|
static bool StatisticsObjIsVisibleExt(Oid stxid, bool *is_missing);
|
||||||
|
static bool TSParserIsVisibleExt(Oid prsId, bool *is_missing);
|
||||||
|
static bool TSDictionaryIsVisibleExt(Oid dictId, bool *is_missing);
|
||||||
|
static bool TSTemplateIsVisibleExt(Oid tmplId, bool *is_missing);
|
||||||
|
static bool TSConfigIsVisibleExt(Oid cfgid, bool *is_missing);
|
||||||
static void recomputeNamespacePath(void);
|
static void recomputeNamespacePath(void);
|
||||||
static void AccessTempTableNamespace(bool force);
|
static void AccessTempTableNamespace(bool force);
|
||||||
static void InitTempTableNamespace(void);
|
static void InitTempTableNamespace(void);
|
||||||
@ -691,6 +704,18 @@ RelnameGetRelid(const char *relname)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
RelationIsVisible(Oid relid)
|
RelationIsVisible(Oid relid)
|
||||||
|
{
|
||||||
|
return RelationIsVisibleExt(relid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RelationIsVisibleExt
|
||||||
|
* As above, but if the relation isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
RelationIsVisibleExt(Oid relid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple reltup;
|
HeapTuple reltup;
|
||||||
Form_pg_class relform;
|
Form_pg_class relform;
|
||||||
@ -699,7 +724,14 @@ RelationIsVisible(Oid relid)
|
|||||||
|
|
||||||
reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
||||||
if (!HeapTupleIsValid(reltup))
|
if (!HeapTupleIsValid(reltup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for relation %u", relid);
|
elog(ERROR, "cache lookup failed for relation %u", relid);
|
||||||
|
}
|
||||||
relform = (Form_pg_class) GETSTRUCT(reltup);
|
relform = (Form_pg_class) GETSTRUCT(reltup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -799,6 +831,18 @@ TypenameGetTypidExtended(const char *typname, bool temp_ok)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
TypeIsVisible(Oid typid)
|
TypeIsVisible(Oid typid)
|
||||||
|
{
|
||||||
|
return TypeIsVisibleExt(typid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TypeIsVisibleExt
|
||||||
|
* As above, but if the type isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
TypeIsVisibleExt(Oid typid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple typtup;
|
HeapTuple typtup;
|
||||||
Form_pg_type typform;
|
Form_pg_type typform;
|
||||||
@ -807,7 +851,14 @@ TypeIsVisible(Oid typid)
|
|||||||
|
|
||||||
typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
|
typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
|
||||||
if (!HeapTupleIsValid(typtup))
|
if (!HeapTupleIsValid(typtup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for type %u", typid);
|
elog(ERROR, "cache lookup failed for type %u", typid);
|
||||||
|
}
|
||||||
typform = (Form_pg_type) GETSTRUCT(typtup);
|
typform = (Form_pg_type) GETSTRUCT(typtup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -1436,6 +1487,18 @@ MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
FunctionIsVisible(Oid funcid)
|
FunctionIsVisible(Oid funcid)
|
||||||
|
{
|
||||||
|
return FunctionIsVisibleExt(funcid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FunctionIsVisibleExt
|
||||||
|
* As above, but if the function isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
FunctionIsVisibleExt(Oid funcid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple proctup;
|
HeapTuple proctup;
|
||||||
Form_pg_proc procform;
|
Form_pg_proc procform;
|
||||||
@ -1444,7 +1507,14 @@ FunctionIsVisible(Oid funcid)
|
|||||||
|
|
||||||
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
|
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
|
||||||
if (!HeapTupleIsValid(proctup))
|
if (!HeapTupleIsValid(proctup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for function %u", funcid);
|
elog(ERROR, "cache lookup failed for function %u", funcid);
|
||||||
|
}
|
||||||
procform = (Form_pg_proc) GETSTRUCT(proctup);
|
procform = (Form_pg_proc) GETSTRUCT(proctup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -1770,6 +1840,18 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
OperatorIsVisible(Oid oprid)
|
OperatorIsVisible(Oid oprid)
|
||||||
|
{
|
||||||
|
return OperatorIsVisibleExt(oprid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OperatorIsVisibleExt
|
||||||
|
* As above, but if the operator isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
OperatorIsVisibleExt(Oid oprid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple oprtup;
|
HeapTuple oprtup;
|
||||||
Form_pg_operator oprform;
|
Form_pg_operator oprform;
|
||||||
@ -1778,7 +1860,14 @@ OperatorIsVisible(Oid oprid)
|
|||||||
|
|
||||||
oprtup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
|
oprtup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
|
||||||
if (!HeapTupleIsValid(oprtup))
|
if (!HeapTupleIsValid(oprtup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for operator %u", oprid);
|
elog(ERROR, "cache lookup failed for operator %u", oprid);
|
||||||
|
}
|
||||||
oprform = (Form_pg_operator) GETSTRUCT(oprtup);
|
oprform = (Form_pg_operator) GETSTRUCT(oprtup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -1856,6 +1945,18 @@ OpclassnameGetOpcid(Oid amid, const char *opcname)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
OpclassIsVisible(Oid opcid)
|
OpclassIsVisible(Oid opcid)
|
||||||
|
{
|
||||||
|
return OpclassIsVisibleExt(opcid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OpclassIsVisibleExt
|
||||||
|
* As above, but if the opclass isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
OpclassIsVisibleExt(Oid opcid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple opctup;
|
HeapTuple opctup;
|
||||||
Form_pg_opclass opcform;
|
Form_pg_opclass opcform;
|
||||||
@ -1864,7 +1965,14 @@ OpclassIsVisible(Oid opcid)
|
|||||||
|
|
||||||
opctup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcid));
|
opctup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcid));
|
||||||
if (!HeapTupleIsValid(opctup))
|
if (!HeapTupleIsValid(opctup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for opclass %u", opcid);
|
elog(ERROR, "cache lookup failed for opclass %u", opcid);
|
||||||
|
}
|
||||||
opcform = (Form_pg_opclass) GETSTRUCT(opctup);
|
opcform = (Form_pg_opclass) GETSTRUCT(opctup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -1939,6 +2047,18 @@ OpfamilynameGetOpfid(Oid amid, const char *opfname)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
OpfamilyIsVisible(Oid opfid)
|
OpfamilyIsVisible(Oid opfid)
|
||||||
|
{
|
||||||
|
return OpfamilyIsVisibleExt(opfid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OpfamilyIsVisibleExt
|
||||||
|
* As above, but if the opfamily isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
OpfamilyIsVisibleExt(Oid opfid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple opftup;
|
HeapTuple opftup;
|
||||||
Form_pg_opfamily opfform;
|
Form_pg_opfamily opfform;
|
||||||
@ -1947,7 +2067,14 @@ OpfamilyIsVisible(Oid opfid)
|
|||||||
|
|
||||||
opftup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
|
opftup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
|
||||||
if (!HeapTupleIsValid(opftup))
|
if (!HeapTupleIsValid(opftup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for opfamily %u", opfid);
|
elog(ERROR, "cache lookup failed for opfamily %u", opfid);
|
||||||
|
}
|
||||||
opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
|
opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -2071,6 +2198,18 @@ CollationGetCollid(const char *collname)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
CollationIsVisible(Oid collid)
|
CollationIsVisible(Oid collid)
|
||||||
|
{
|
||||||
|
return CollationIsVisibleExt(collid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CollationIsVisibleExt
|
||||||
|
* As above, but if the collation isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
CollationIsVisibleExt(Oid collid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple colltup;
|
HeapTuple colltup;
|
||||||
Form_pg_collation collform;
|
Form_pg_collation collform;
|
||||||
@ -2079,7 +2218,14 @@ CollationIsVisible(Oid collid)
|
|||||||
|
|
||||||
colltup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
|
colltup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
|
||||||
if (!HeapTupleIsValid(colltup))
|
if (!HeapTupleIsValid(colltup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for collation %u", collid);
|
elog(ERROR, "cache lookup failed for collation %u", collid);
|
||||||
|
}
|
||||||
collform = (Form_pg_collation) GETSTRUCT(colltup);
|
collform = (Form_pg_collation) GETSTRUCT(colltup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -2154,6 +2300,18 @@ ConversionGetConid(const char *conname)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
ConversionIsVisible(Oid conid)
|
ConversionIsVisible(Oid conid)
|
||||||
|
{
|
||||||
|
return ConversionIsVisibleExt(conid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ConversionIsVisibleExt
|
||||||
|
* As above, but if the conversion isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ConversionIsVisibleExt(Oid conid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple contup;
|
HeapTuple contup;
|
||||||
Form_pg_conversion conform;
|
Form_pg_conversion conform;
|
||||||
@ -2162,7 +2320,14 @@ ConversionIsVisible(Oid conid)
|
|||||||
|
|
||||||
contup = SearchSysCache1(CONVOID, ObjectIdGetDatum(conid));
|
contup = SearchSysCache1(CONVOID, ObjectIdGetDatum(conid));
|
||||||
if (!HeapTupleIsValid(contup))
|
if (!HeapTupleIsValid(contup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for conversion %u", conid);
|
elog(ERROR, "cache lookup failed for conversion %u", conid);
|
||||||
|
}
|
||||||
conform = (Form_pg_conversion) GETSTRUCT(contup);
|
conform = (Form_pg_conversion) GETSTRUCT(contup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -2257,16 +2422,35 @@ get_statistics_object_oid(List *names, bool missing_ok)
|
|||||||
* for the unqualified statistics object name".
|
* for the unqualified statistics object name".
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
StatisticsObjIsVisible(Oid relid)
|
StatisticsObjIsVisible(Oid stxid)
|
||||||
|
{
|
||||||
|
return StatisticsObjIsVisibleExt(stxid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatisticsObjIsVisibleExt
|
||||||
|
* As above, but if the statistics object isn't found and is_missing is
|
||||||
|
* not NULL, then set *is_missing = true and return false instead of
|
||||||
|
* throwing an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
StatisticsObjIsVisibleExt(Oid stxid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple stxtup;
|
HeapTuple stxtup;
|
||||||
Form_pg_statistic_ext stxform;
|
Form_pg_statistic_ext stxform;
|
||||||
Oid stxnamespace;
|
Oid stxnamespace;
|
||||||
bool visible;
|
bool visible;
|
||||||
|
|
||||||
stxtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(relid));
|
stxtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stxid));
|
||||||
if (!HeapTupleIsValid(stxtup))
|
if (!HeapTupleIsValid(stxtup))
|
||||||
elog(ERROR, "cache lookup failed for statistics object %u", relid);
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
elog(ERROR, "cache lookup failed for statistics object %u", stxid);
|
||||||
|
}
|
||||||
stxform = (Form_pg_statistic_ext) GETSTRUCT(stxtup);
|
stxform = (Form_pg_statistic_ext) GETSTRUCT(stxtup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -2381,6 +2565,18 @@ get_ts_parser_oid(List *names, bool missing_ok)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
TSParserIsVisible(Oid prsId)
|
TSParserIsVisible(Oid prsId)
|
||||||
|
{
|
||||||
|
return TSParserIsVisibleExt(prsId, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TSParserIsVisibleExt
|
||||||
|
* As above, but if the parser isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
TSParserIsVisibleExt(Oid prsId, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
Form_pg_ts_parser form;
|
Form_pg_ts_parser form;
|
||||||
@ -2389,7 +2585,14 @@ TSParserIsVisible(Oid prsId)
|
|||||||
|
|
||||||
tup = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId));
|
tup = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId));
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for text search parser %u", prsId);
|
elog(ERROR, "cache lookup failed for text search parser %u", prsId);
|
||||||
|
}
|
||||||
form = (Form_pg_ts_parser) GETSTRUCT(tup);
|
form = (Form_pg_ts_parser) GETSTRUCT(tup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -2507,6 +2710,18 @@ get_ts_dict_oid(List *names, bool missing_ok)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
TSDictionaryIsVisible(Oid dictId)
|
TSDictionaryIsVisible(Oid dictId)
|
||||||
|
{
|
||||||
|
return TSDictionaryIsVisibleExt(dictId, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TSDictionaryIsVisibleExt
|
||||||
|
* As above, but if the dictionary isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
TSDictionaryIsVisibleExt(Oid dictId, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
Form_pg_ts_dict form;
|
Form_pg_ts_dict form;
|
||||||
@ -2515,8 +2730,15 @@ TSDictionaryIsVisible(Oid dictId)
|
|||||||
|
|
||||||
tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
|
tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for text search dictionary %u",
|
elog(ERROR, "cache lookup failed for text search dictionary %u",
|
||||||
dictId);
|
dictId);
|
||||||
|
}
|
||||||
form = (Form_pg_ts_dict) GETSTRUCT(tup);
|
form = (Form_pg_ts_dict) GETSTRUCT(tup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -2634,6 +2856,18 @@ get_ts_template_oid(List *names, bool missing_ok)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
TSTemplateIsVisible(Oid tmplId)
|
TSTemplateIsVisible(Oid tmplId)
|
||||||
|
{
|
||||||
|
return TSTemplateIsVisibleExt(tmplId, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TSTemplateIsVisibleExt
|
||||||
|
* As above, but if the template isn't found and is_missing is not NULL,
|
||||||
|
* then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
TSTemplateIsVisibleExt(Oid tmplId, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
Form_pg_ts_template form;
|
Form_pg_ts_template form;
|
||||||
@ -2642,7 +2876,14 @@ TSTemplateIsVisible(Oid tmplId)
|
|||||||
|
|
||||||
tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
|
tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for text search template %u", tmplId);
|
elog(ERROR, "cache lookup failed for text search template %u", tmplId);
|
||||||
|
}
|
||||||
form = (Form_pg_ts_template) GETSTRUCT(tup);
|
form = (Form_pg_ts_template) GETSTRUCT(tup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -2760,6 +3001,18 @@ get_ts_config_oid(List *names, bool missing_ok)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
TSConfigIsVisible(Oid cfgid)
|
TSConfigIsVisible(Oid cfgid)
|
||||||
|
{
|
||||||
|
return TSConfigIsVisibleExt(cfgid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TSConfigIsVisibleExt
|
||||||
|
* As above, but if the configuration isn't found and is_missing is not
|
||||||
|
* NULL, then set *is_missing = true and return false instead of throwing
|
||||||
|
* an error. (Caller must initialize *is_missing = false.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
TSConfigIsVisibleExt(Oid cfgid, bool *is_missing)
|
||||||
{
|
{
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
Form_pg_ts_config form;
|
Form_pg_ts_config form;
|
||||||
@ -2768,8 +3021,15 @@ TSConfigIsVisible(Oid cfgid)
|
|||||||
|
|
||||||
tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
|
tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
|
{
|
||||||
|
if (is_missing != NULL)
|
||||||
|
{
|
||||||
|
*is_missing = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
elog(ERROR, "cache lookup failed for text search configuration %u",
|
elog(ERROR, "cache lookup failed for text search configuration %u",
|
||||||
cfgid);
|
cfgid);
|
||||||
|
}
|
||||||
form = (Form_pg_ts_config) GETSTRUCT(tup);
|
form = (Form_pg_ts_config) GETSTRUCT(tup);
|
||||||
|
|
||||||
recomputeNamespacePath();
|
recomputeNamespacePath();
|
||||||
@ -4283,152 +4543,189 @@ fetch_search_path_array(Oid *sarray, int sarray_len)
|
|||||||
* condition errors when a query that's scanning a catalog using an MVCC
|
* condition errors when a query that's scanning a catalog using an MVCC
|
||||||
* snapshot uses one of these functions. The underlying IsVisible functions
|
* snapshot uses one of these functions. The underlying IsVisible functions
|
||||||
* always use an up-to-date snapshot and so might see the object as already
|
* always use an up-to-date snapshot and so might see the object as already
|
||||||
* gone when it's still visible to the transaction snapshot. (There is no race
|
* gone when it's still visible to the transaction snapshot.
|
||||||
* condition in the current coding because we don't accept sinval messages
|
|
||||||
* between the SearchSysCacheExists test and the subsequent lookup.)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_table_is_visible(PG_FUNCTION_ARGS)
|
pg_table_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(oid)))
|
result = RelationIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(RelationIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_type_is_visible(PG_FUNCTION_ARGS)
|
pg_type_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(oid)))
|
result = TypeIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(TypeIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_function_is_visible(PG_FUNCTION_ARGS)
|
pg_function_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(oid)))
|
result = FunctionIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(FunctionIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_operator_is_visible(PG_FUNCTION_ARGS)
|
pg_operator_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(OPEROID, ObjectIdGetDatum(oid)))
|
result = OperatorIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(OperatorIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_opclass_is_visible(PG_FUNCTION_ARGS)
|
pg_opclass_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(CLAOID, ObjectIdGetDatum(oid)))
|
result = OpclassIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(OpclassIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_opfamily_is_visible(PG_FUNCTION_ARGS)
|
pg_opfamily_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(OPFAMILYOID, ObjectIdGetDatum(oid)))
|
result = OpfamilyIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(OpfamilyIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_collation_is_visible(PG_FUNCTION_ARGS)
|
pg_collation_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(COLLOID, ObjectIdGetDatum(oid)))
|
result = CollationIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(CollationIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_conversion_is_visible(PG_FUNCTION_ARGS)
|
pg_conversion_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(CONVOID, ObjectIdGetDatum(oid)))
|
result = ConversionIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(ConversionIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_statistics_obj_is_visible(PG_FUNCTION_ARGS)
|
pg_statistics_obj_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(STATEXTOID, ObjectIdGetDatum(oid)))
|
result = StatisticsObjIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(StatisticsObjIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_ts_parser_is_visible(PG_FUNCTION_ARGS)
|
pg_ts_parser_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(TSPARSEROID, ObjectIdGetDatum(oid)))
|
result = TSParserIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(TSParserIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_ts_dict_is_visible(PG_FUNCTION_ARGS)
|
pg_ts_dict_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(TSDICTOID, ObjectIdGetDatum(oid)))
|
result = TSDictionaryIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(TSDictionaryIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_ts_template_is_visible(PG_FUNCTION_ARGS)
|
pg_ts_template_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(TSTEMPLATEOID, ObjectIdGetDatum(oid)))
|
result = TSTemplateIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(TSTemplateIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
pg_ts_config_is_visible(PG_FUNCTION_ARGS)
|
pg_ts_config_is_visible(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Oid oid = PG_GETARG_OID(0);
|
Oid oid = PG_GETARG_OID(0);
|
||||||
|
bool result;
|
||||||
|
bool is_missing = false;
|
||||||
|
|
||||||
if (!SearchSysCacheExists1(TSCONFIGOID, ObjectIdGetDatum(oid)))
|
result = TSConfigIsVisibleExt(oid, &is_missing);
|
||||||
|
|
||||||
|
if (is_missing)
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
PG_RETURN_BOOL(TSConfigIsVisible(oid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
|
@ -122,7 +122,7 @@ extern Oid ConversionGetConid(const char *conname);
|
|||||||
extern bool ConversionIsVisible(Oid conid);
|
extern bool ConversionIsVisible(Oid conid);
|
||||||
|
|
||||||
extern Oid get_statistics_object_oid(List *names, bool missing_ok);
|
extern Oid get_statistics_object_oid(List *names, bool missing_ok);
|
||||||
extern bool StatisticsObjIsVisible(Oid relid);
|
extern bool StatisticsObjIsVisible(Oid stxid);
|
||||||
|
|
||||||
extern Oid get_ts_parser_oid(List *names, bool missing_ok);
|
extern Oid get_ts_parser_oid(List *names, bool missing_ok);
|
||||||
extern bool TSParserIsVisible(Oid prsId);
|
extern bool TSParserIsVisible(Oid prsId);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user