Give better hints for ambiguous or unreferenceable columns.

Examine ParseNamespaceItem flags to detect whether a column name
is unreferenceable for lack of LATERAL, or could be referenced if
a qualified name were used, and give better hints for such cases.
Also, don't phrase the message to imply that there's only one
matching column when there is really more than one.

Many of the regression test output changes are not very interesting,
but just reflect reclassifying the "There is a column ... but it
cannot be referenced from this part of the query" messages as DETAIL
rather than HINT.  They are details per our style guide, in the sense
of being factual rather than offering advice; and this change provides
room to offer actual HINTs about what to do.

While here, adjust the fuzzy-name-matching code to be a shade less
impenetrable.  It was overloading the meanings of FuzzyAttrMatchState
fields way too much IMO, so splitting them into multiple fields seems
to make it clearer.  It's not like we need to shave bytes in that
struct.

Per discussion of bug #17233 from Alexander Korolev.

Discussion: https://postgr.es/m/17233-afb9d806aaa64b17@postgresql.org
This commit is contained in:
Tom Lane 2022-11-22 18:46:31 -05:00
parent 9c6ad5eaa9
commit 56d0ed3b75
7 changed files with 233 additions and 106 deletions

View File

@ -41,17 +41,35 @@
/*
* Support for fuzzily matching columns.
*
* This is for building diagnostic messages, where non-exact matching
* attributes are suggested to the user. The struct's fields may be facets of
* a particular RTE, or of an entire range table, depending on context.
* This is for building diagnostic messages, where multiple or non-exact
* matching attributes are of interest.
*
* "distance" is the current best fuzzy-match distance if rfirst isn't NULL,
* otherwise it is the maximum acceptable distance plus 1.
*
* rfirst/first record the closest non-exact match so far, and distance
* is its distance from the target name. If we have found a second non-exact
* match of exactly the same distance, rsecond/second record that. (If
* we find three of the same distance, we conclude that "distance" is not
* a tight enough bound for a useful hint and clear rfirst/rsecond again.
* Only if we later find something closer will we re-populate rfirst.)
*
* rexact1/exact1 record the location of the first exactly-matching column,
* if any. If we find multiple exact matches then rexact2/exact2 record
* another one (we don't especially care which). Currently, these get
* populated independently of the fuzzy-match fields.
*/
typedef struct
{
int distance; /* Weighted distance (lowest so far) */
RangeTblEntry *rfirst; /* RTE of first */
AttrNumber first; /* Closest attribute so far */
RangeTblEntry *rsecond; /* RTE of second */
AttrNumber second; /* Second closest attribute so far */
int distance; /* Current or limit distance */
RangeTblEntry *rfirst; /* RTE of closest non-exact match, or NULL */
AttrNumber first; /* Col index in rfirst */
RangeTblEntry *rsecond; /* RTE of another non-exact match w/same dist */
AttrNumber second; /* Col index in rsecond */
RangeTblEntry *rexact1; /* RTE of first exact match, or NULL */
AttrNumber exact1; /* Col index in rexact1 */
RangeTblEntry *rexact2; /* RTE of second exact match, or NULL */
AttrNumber exact2; /* Col index in rexact2 */
} FuzzyAttrMatchState;
#define MAX_FUZZY_DISTANCE 3
@ -81,6 +99,8 @@ static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
int location, bool include_dropped,
List **colnames, List **colvars);
static int specialAttNum(const char *attname);
static bool rte_visible_if_lateral(ParseState *pstate, RangeTblEntry *rte);
static bool rte_visible_if_qualified(ParseState *pstate, RangeTblEntry *rte);
static bool isQueryUsingTempRelation_walker(Node *node, void *context);
@ -610,47 +630,39 @@ updateFuzzyAttrMatchState(int fuzzy_rte_penalty,
*/
if (columndistance < fuzzystate->distance)
{
/* Store new lowest observed distance for RTE */
/* Store new lowest observed distance as first/only match */
fuzzystate->distance = columndistance;
fuzzystate->rfirst = rte;
fuzzystate->first = attnum;
fuzzystate->rsecond = NULL;
fuzzystate->second = InvalidAttrNumber;
}
else if (columndistance == fuzzystate->distance)
{
/*
* This match distance may equal a prior match within this same range
* table. When that happens, the prior match may also be given, but
* only if there is no more than two equally distant matches from the
* RTE (in turn, our caller will only accept two equally distant
* matches overall).
*/
if (AttributeNumberIsValid(fuzzystate->second))
/* If we already have a match of this distance, update state */
if (fuzzystate->rsecond != NULL)
{
/* Too many RTE-level matches */
/*
* Too many matches at same distance. Clearly, this value of
* distance is too low a bar, so drop these entries while keeping
* the current distance value, so that only smaller distances will
* be considered interesting. Only if we find something of lower
* distance will we re-populate rfirst (via the stanza above).
*/
fuzzystate->rfirst = NULL;
fuzzystate->first = InvalidAttrNumber;
fuzzystate->rsecond = NULL;
fuzzystate->second = InvalidAttrNumber;
/* Clearly, distance is too low a bar (for *any* RTE) */
fuzzystate->distance = columndistance - 1;
}
else if (AttributeNumberIsValid(fuzzystate->first))
else if (fuzzystate->rfirst != NULL)
{
/* Record as provisional second match for RTE */
/* Record as provisional second match */
fuzzystate->rsecond = rte;
fuzzystate->second = attnum;
}
else if (fuzzystate->distance <= MAX_FUZZY_DISTANCE)
else
{
/*
* Record as provisional first match (this can occasionally occur
* because previous lowest distance was "too low a bar", rather
* than being associated with a real match)
* Do nothing. When rfirst is NULL, distance is more than what we
* want to consider acceptable, so we should ignore this match.
*/
fuzzystate->rfirst = rte;
fuzzystate->first = attnum;
}
}
}
@ -923,21 +935,15 @@ colNameToVar(ParseState *pstate, const char *colname, bool localonly,
* This is different from colNameToVar in that it considers every entry in
* the ParseState's rangetable(s), not only those that are currently visible
* in the p_namespace list(s). This behavior is invalid per the SQL spec,
* and it may give ambiguous results (there might be multiple equally valid
* matches, but only one will be returned). This must be used ONLY as a
* heuristic in giving suitable error messages. See errorMissingColumn.
* and it may give ambiguous results (since there might be multiple equally
* valid matches). This must be used ONLY as a heuristic in giving suitable
* error messages. See errorMissingColumn.
*
* This function is also different in that it will consider approximate
* matches -- if the user entered an alias/column pair that is only slightly
* different from a valid pair, we may be able to infer what they meant to
* type and provide a reasonable hint.
*
* The FuzzyAttrMatchState will have 'rfirst' pointing to the best RTE
* containing the most promising match for the alias and column name. If
* the alias and column names match exactly, 'first' will be InvalidAttrNumber;
* otherwise, it will be the attribute number for the match. In the latter
* case, 'rsecond' may point to a second, equally close approximate match,
* and 'second' will contain the attribute number for the second match.
* type and provide a reasonable hint. We return a FuzzyAttrMatchState
* struct providing information about both exact and approximate matches.
*/
static FuzzyAttrMatchState *
searchRangeTableForCol(ParseState *pstate, const char *alias, const char *colname,
@ -949,8 +955,8 @@ searchRangeTableForCol(ParseState *pstate, const char *alias, const char *colnam
fuzzystate->distance = MAX_FUZZY_DISTANCE + 1;
fuzzystate->rfirst = NULL;
fuzzystate->rsecond = NULL;
fuzzystate->first = InvalidAttrNumber;
fuzzystate->second = InvalidAttrNumber;
fuzzystate->rexact1 = NULL;
fuzzystate->rexact2 = NULL;
while (pstate != NULL)
{
@ -960,6 +966,7 @@ searchRangeTableForCol(ParseState *pstate, const char *alias, const char *colnam
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
int fuzzy_rte_penalty = 0;
int attnum;
/*
* Typically, it is not useful to look for matches within join
@ -986,18 +993,27 @@ searchRangeTableForCol(ParseState *pstate, const char *alias, const char *colnam
true);
/*
* Scan for a matching column; if we find an exact match, we're
* done. Otherwise, update fuzzystate.
* Scan for a matching column, and update fuzzystate. Non-exact
* matches are dealt with inside scanRTEForColumn, but exact
* matches are handled here. (There won't be more than one exact
* match in the same RTE, else we'd have thrown error earlier.)
*/
if (scanRTEForColumn(orig_pstate, rte, rte->eref, colname, location,
fuzzy_rte_penalty, fuzzystate)
&& fuzzy_rte_penalty == 0)
attnum = scanRTEForColumn(orig_pstate, rte, rte->eref,
colname, location,
fuzzy_rte_penalty, fuzzystate);
if (attnum != InvalidAttrNumber && fuzzy_rte_penalty == 0)
{
fuzzystate->rfirst = rte;
fuzzystate->first = InvalidAttrNumber;
fuzzystate->rsecond = NULL;
fuzzystate->second = InvalidAttrNumber;
return fuzzystate;
if (fuzzystate->rexact1 == NULL)
{
fuzzystate->rexact1 = rte;
fuzzystate->exact1 = attnum;
}
else
{
/* Needn't worry about overwriting previous rexact2 */
fuzzystate->rexact2 = rte;
fuzzystate->exact2 = attnum;
}
}
}
@ -3603,17 +3619,27 @@ errorMissingRTE(ParseState *pstate, RangeVar *relation)
badAlias = rte->eref->aliasname;
}
if (rte)
/* If it looks like the user forgot to use an alias, hint about that */
if (badAlias)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
relation->relname),
(badAlias ?
errhint("Perhaps you meant to reference the table alias \"%s\".",
badAlias) :
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
rte->eref->aliasname)),
errhint("Perhaps you meant to reference the table alias \"%s\".",
badAlias),
parser_errposition(pstate, relation->location)));
/* Hint about case where we found an (inaccessible) exact match */
else if (rte)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
relation->relname),
errdetail("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
rte->eref->aliasname),
rte_visible_if_lateral(pstate, rte) ?
errhint("To reference that table, you must mark this subquery with LATERAL.") : 0,
parser_errposition(pstate, relation->location)));
/* Else, we have nothing to offer but the bald statement of error */
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
@ -3633,68 +3659,155 @@ errorMissingColumn(ParseState *pstate,
const char *relname, const char *colname, int location)
{
FuzzyAttrMatchState *state;
char *closestfirst = NULL;
/*
* Search the entire rtable looking for possible matches. If we find one,
* emit a hint about it.
*
* TODO: improve this code (and also errorMissingRTE) to mention using
* LATERAL if appropriate.
*/
state = searchRangeTableForCol(pstate, relname, colname, location);
/*
* Extract closest col string for best match, if any.
*
* Infer an exact match referenced despite not being visible from the fact
* that an attribute number was not present in state passed back -- this
* is what is reported when !closestfirst. There might also be an exact
* match that was qualified with an incorrect alias, in which case
* closestfirst will be set (so hint is the same as generic fuzzy case).
* If there are exact match(es), they must be inaccessible for some
* reason.
*/
if (state->rfirst && AttributeNumberIsValid(state->first))
closestfirst = strVal(list_nth(state->rfirst->eref->colnames,
state->first - 1));
if (!state->rsecond)
if (state->rexact1)
{
/*
* Handle case where there is zero or one column suggestions to hint,
* including exact matches referenced but not visible.
* We don't try too hard when there's multiple inaccessible exact
* matches, but at least be sure that we don't misleadingly suggest
* that there's only one.
*/
if (state->rexact2)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
errdetail("There are columns named \"%s\", but they are in tables that cannot be referenced from this part of the query.",
colname),
!relname ? errhint("Try using a table-qualified name.") : 0,
parser_errposition(pstate, location)));
/* Single exact match, so try to determine why it's inaccessible. */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
errdetail("There is a column named \"%s\" in table \"%s\", but it cannot be referenced from this part of the query.",
colname, state->rexact1->eref->aliasname),
rte_visible_if_lateral(pstate, state->rexact1) ?
errhint("To reference that column, you must mark this subquery with LATERAL.") :
(!relname && rte_visible_if_qualified(pstate, state->rexact1)) ?
errhint("To reference that column, you must use a table-qualified name.") : 0,
parser_errposition(pstate, location)));
}
if (!state->rsecond)
{
/* If we found no match at all, we have little to report */
if (!state->rfirst)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
parser_errposition(pstate, location)));
/* Handle case where we have a single alternative spelling to offer */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
state->rfirst ? closestfirst ?
errhint("Perhaps you meant to reference the column \"%s.%s\".",
state->rfirst->eref->aliasname, closestfirst) :
errhint("There is a column named \"%s\" in table \"%s\", but it cannot be referenced from this part of the query.",
colname, state->rfirst->eref->aliasname) : 0,
state->rfirst->eref->aliasname,
strVal(list_nth(state->rfirst->eref->colnames,
state->first - 1))),
parser_errposition(pstate, location)));
}
else
{
/* Handle case where there are two equally useful column hints */
char *closestsecond;
closestsecond = strVal(list_nth(state->rsecond->eref->colnames,
state->second - 1));
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
errhint("Perhaps you meant to reference the column \"%s.%s\" or the column \"%s.%s\".",
state->rfirst->eref->aliasname, closestfirst,
state->rsecond->eref->aliasname, closestsecond),
state->rfirst->eref->aliasname,
strVal(list_nth(state->rfirst->eref->colnames,
state->first - 1)),
state->rsecond->eref->aliasname,
strVal(list_nth(state->rsecond->eref->colnames,
state->second - 1))),
parser_errposition(pstate, location)));
}
}
/*
* Find ParseNamespaceItem for RTE, if it's visible at all.
* We assume an RTE couldn't appear more than once in the namespace lists.
*/
static ParseNamespaceItem *
findNSItemForRTE(ParseState *pstate, RangeTblEntry *rte)
{
while (pstate != NULL)
{
ListCell *l;
foreach(l, pstate->p_namespace)
{
ParseNamespaceItem *nsitem = (ParseNamespaceItem *) lfirst(l);
if (nsitem->p_rte == rte)
return nsitem;
}
pstate = pstate->parentParseState;
}
return NULL;
}
/*
* Would this RTE be visible, if only the user had written LATERAL?
*
* This is a helper for deciding whether to issue a HINT about LATERAL.
* As such, it doesn't need to be 100% accurate; the HINT could be useful
* even if it's not quite right. Hence, we don't delve into fine points
* about whether a found nsitem has the appropriate one of p_rel_visible or
* p_cols_visible set.
*/
static bool
rte_visible_if_lateral(ParseState *pstate, RangeTblEntry *rte)
{
ParseNamespaceItem *nsitem;
/* If LATERAL *is* active, we're clearly barking up the wrong tree */
if (pstate->p_lateral_active)
return false;
nsitem = findNSItemForRTE(pstate, rte);
if (nsitem)
{
/* Found it, report whether it's LATERAL-only */
return nsitem->p_lateral_only && nsitem->p_lateral_ok;
}
return false;
}
/*
* Would columns in this RTE be visible if qualified?
*/
static bool
rte_visible_if_qualified(ParseState *pstate, RangeTblEntry *rte)
{
ParseNamespaceItem *nsitem = findNSItemForRTE(pstate, rte);
if (nsitem)
{
/* Found it, report whether it's relation-only */
return nsitem->p_rel_visible && !nsitem->p_cols_visible;
}
return false;
}
/*
* Examine a fully-parsed query, and return true iff any relation underlying

View File

@ -242,7 +242,7 @@ insert into insertconflicttest values (1, 'Apple') on conflict (key) do update s
ERROR: invalid reference to FROM-clause entry for table "excluded"
LINE 1: ...y) do update set fruit = excluded.fruit RETURNING excluded.f...
^
HINT: There is an entry for table "excluded", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "excluded", but it cannot be referenced from this part of the query.
-- Only suggest <table>.* column when inference element misspelled:
insert into insertconflicttest values (1, 'Apple') on conflict (keyy) do update set fruit = excluded.fruit;
ERROR: column "keyy" does not exist

View File

@ -1638,7 +1638,7 @@ SELECT * FROM (J1_TBL JOIN J2_TBL USING (i)) AS x WHERE J1_TBL.t = 'one'; -- er
ERROR: invalid reference to FROM-clause entry for table "j1_tbl"
LINE 1: ... * FROM (J1_TBL JOIN J2_TBL USING (i)) AS x WHERE J1_TBL.t =...
^
HINT: There is an entry for table "j1_tbl", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "j1_tbl", but it cannot be referenced from this part of the query.
SELECT * FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE x.i = 1; -- ok
i | j | t | k
---+---+-----+----
@ -5064,7 +5064,7 @@ select * from
ERROR: invalid reference to FROM-clause entry for table "y"
LINE 2: ...bl x join (int4_tbl x cross join int4_tbl y) j on q1 = y.f1;
^
HINT: There is an entry for table "y", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "y", but it cannot be referenced from this part of the query.
select * from
int8_tbl x join (int4_tbl x cross join int4_tbl y(ff)) j on q1 = f1; -- ok
q1 | q2 | f1 | ff
@ -5092,6 +5092,13 @@ ERROR: column "uunique1" does not exist
LINE 1: select uunique1 from
^
HINT: Perhaps you meant to reference the column "t1.unique1" or the column "t2.unique1".
select ctid from
tenk1 t1 join tenk2 t2 on t1.two = t2.two; -- error, need qualification
ERROR: column "ctid" does not exist
LINE 1: select ctid from
^
DETAIL: There are columns named "ctid", but they are in tables that cannot be referenced from this part of the query.
HINT: Try using a table-qualified name.
--
-- Take care to reference the correct RTE
--
@ -6125,22 +6132,26 @@ select f1,g from int4_tbl a, (select f1 as g) ss;
ERROR: column "f1" does not exist
LINE 1: select f1,g from int4_tbl a, (select f1 as g) ss;
^
HINT: There is a column named "f1" in table "a", but it cannot be referenced from this part of the query.
DETAIL: There is a column named "f1" in table "a", but it cannot be referenced from this part of the query.
HINT: To reference that column, you must mark this subquery with LATERAL.
select f1,g from int4_tbl a, (select a.f1 as g) ss;
ERROR: invalid reference to FROM-clause entry for table "a"
LINE 1: select f1,g from int4_tbl a, (select a.f1 as g) ss;
^
HINT: There is an entry for table "a", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "a", but it cannot be referenced from this part of the query.
HINT: To reference that table, you must mark this subquery with LATERAL.
select f1,g from int4_tbl a cross join (select f1 as g) ss;
ERROR: column "f1" does not exist
LINE 1: select f1,g from int4_tbl a cross join (select f1 as g) ss;
^
HINT: There is a column named "f1" in table "a", but it cannot be referenced from this part of the query.
DETAIL: There is a column named "f1" in table "a", but it cannot be referenced from this part of the query.
HINT: To reference that column, you must mark this subquery with LATERAL.
select f1,g from int4_tbl a cross join (select a.f1 as g) ss;
ERROR: invalid reference to FROM-clause entry for table "a"
LINE 1: select f1,g from int4_tbl a cross join (select a.f1 as g) ss...
^
HINT: There is an entry for table "a", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "a", but it cannot be referenced from this part of the query.
HINT: To reference that table, you must mark this subquery with LATERAL.
-- SQL:2008 says the left table is in scope but illegal to access here
select f1,g from int4_tbl a right join lateral generate_series(0, a.f1) g on true;
ERROR: invalid reference to FROM-clause entry for table "a"
@ -6170,12 +6181,12 @@ update xx1 set x2 = f1 from (select * from int4_tbl where f1 = x1) ss;
ERROR: column "x1" does not exist
LINE 1: ... set x2 = f1 from (select * from int4_tbl where f1 = x1) ss;
^
HINT: There is a column named "x1" in table "xx1", but it cannot be referenced from this part of the query.
DETAIL: There is a column named "x1" in table "xx1", but it cannot be referenced from this part of the query.
update xx1 set x2 = f1 from (select * from int4_tbl where f1 = xx1.x1) ss;
ERROR: invalid reference to FROM-clause entry for table "xx1"
LINE 1: ...t x2 = f1 from (select * from int4_tbl where f1 = xx1.x1) ss...
^
HINT: There is an entry for table "xx1", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "xx1", but it cannot be referenced from this part of the query.
-- can't do it even with LATERAL:
update xx1 set x2 = f1 from lateral (select * from int4_tbl where f1 = x1) ss;
ERROR: invalid reference to FROM-clause entry for table "xx1"
@ -6190,12 +6201,12 @@ delete from xx1 using (select * from int4_tbl where f1 = x1) ss;
ERROR: column "x1" does not exist
LINE 1: ...te from xx1 using (select * from int4_tbl where f1 = x1) ss;
^
HINT: There is a column named "x1" in table "xx1", but it cannot be referenced from this part of the query.
DETAIL: There is a column named "x1" in table "xx1", but it cannot be referenced from this part of the query.
delete from xx1 using (select * from int4_tbl where f1 = xx1.x1) ss;
ERROR: invalid reference to FROM-clause entry for table "xx1"
LINE 1: ...from xx1 using (select * from int4_tbl where f1 = xx1.x1) ss...
^
HINT: There is an entry for table "xx1", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "xx1", but it cannot be referenced from this part of the query.
delete from xx1 using lateral (select * from int4_tbl where f1 = x1) ss;
ERROR: invalid reference to FROM-clause entry for table "xx1"
LINE 1: ...xx1 using lateral (select * from int4_tbl where f1 = x1) ss;

View File

@ -197,7 +197,7 @@ WHEN NOT MATCHED THEN
ERROR: invalid reference to FROM-clause entry for table "t"
LINE 2: USING (SELECT * FROM source WHERE t.tid > sid) s
^
HINT: There is an entry for table "t", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "t", but it cannot be referenced from this part of the query.
--
-- initial tests
--
@ -618,7 +618,7 @@ WHEN NOT MATCHED THEN
ERROR: invalid reference to FROM-clause entry for table "t"
LINE 5: INSERT (tid, balance) VALUES (t.tid, s.delta);
^
HINT: There is an entry for table "t", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "t", but it cannot be referenced from this part of the query.
-- and again with a constant ON clause
BEGIN;
MERGE INTO target t
@ -629,7 +629,7 @@ WHEN NOT MATCHED THEN
ERROR: invalid reference to FROM-clause entry for table "t"
LINE 5: INSERT (tid, balance) VALUES (t.tid, s.delta);
^
HINT: There is an entry for table "t", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "t", but it cannot be referenced from this part of the query.
SELECT * FROM target ORDER BY tid;
ERROR: current transaction is aborted, commands ignored until end of transaction block
ROLLBACK;
@ -724,7 +724,7 @@ WHEN NOT MATCHED AND t.balance = 100 THEN
ERROR: invalid reference to FROM-clause entry for table "t"
LINE 3: WHEN NOT MATCHED AND t.balance = 100 THEN
^
HINT: There is an entry for table "t", but it cannot be referenced from this part of the query.
DETAIL: There is an entry for table "t", but it cannot be referenced from this part of the query.
SELECT * FROM wq_target;
ERROR: current transaction is aborted, commands ignored until end of transaction block
ROLLBACK;

View File

@ -1194,7 +1194,8 @@ do instead insert into rules_foo2 values (f1);
ERROR: column "f1" does not exist
LINE 2: do instead insert into rules_foo2 values (f1);
^
HINT: There is a column named "f1" in table "old", but it cannot be referenced from this part of the query.
DETAIL: There are columns named "f1", but they are in tables that cannot be referenced from this part of the query.
HINT: Try using a table-qualified name.
-- this is the correct way:
create rule rules_foorule as on insert to rules_foo where f1 < 100
do instead insert into rules_foo2 values (new.f1);

View File

@ -910,7 +910,7 @@ SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1;
ERROR: column "q2" does not exist
LINE 1: ... int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1...
^
HINT: There is a column named "q2" in table "*SELECT* 2", but it cannot be referenced from this part of the query.
DETAIL: There is a column named "q2" in table "*SELECT* 2", but it cannot be referenced from this part of the query.
-- But this should work:
SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1))) ORDER BY 1;
q1

View File

@ -1841,6 +1841,8 @@ select t2.uunique1 from
tenk1 t1 join tenk2 t2 on t1.two = t2.two; -- error, prefer "t2" suggestion
select uunique1 from
tenk1 t1 join tenk2 t2 on t1.two = t2.two; -- error, suggest both at once
select ctid from
tenk1 t1 join tenk2 t2 on t1.two = t2.two; -- error, need qualification
--
-- Take care to reference the correct RTE