0001-refactor-isolate-relation-errors-to-a-function.patch
text/x-patch
Filename: 0001-refactor-isolate-relation-errors-to-a-function.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0001
Subject: refactor: isolate relation errors to a function
| File | + | − |
|---|---|---|
| src/backend/parser/parse_relation.c | 40 | 34 |
From 9a500e02535b09051816a55ebb6f75e4421da270 Mon Sep 17 00:00:00 2001
From: steve-chavez <stevechavezast@gmail.com>
Date: Mon, 1 Dec 2025 20:13:36 -0500
Subject: [PATCH 1/2] refactor: isolate relation errors to a function
Also add levenshtein_is_absurd explaining more about the formula used.
---
src/backend/parser/parse_relation.c | 74 ++++++++++++++++-------------
1 file changed, 40 insertions(+), 34 deletions(-)
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index d544a69fc80..c1563f1b51b 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -101,6 +101,8 @@ 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 inline bool levenshtein_is_absurd(int distance, int matchlen);
+static void errorMissingRelation(ParseState *pstate, const RangeVar *relation);
/*
* refnameNamespaceItem
@@ -615,11 +617,7 @@ updateFuzzyAttrMatchState(int fuzzy_rte_penalty,
- fuzzy_rte_penalty,
true);
- /*
- * If more than half the characters are different, don't treat it as a
- * match, to avoid making ridiculous suggestions.
- */
- if (columndistance > matchlen / 2)
+ if (levenshtein_is_absurd(columndistance, matchlen))
return;
/*
@@ -1416,6 +1414,31 @@ buildNSItemFromLists(RangeTblEntry *rte, Index rtindex,
return nsitem;
}
+void
+errorMissingRelation(ParseState *pstate, const RangeVar *relation)
+{
+ /*
+ * An unqualified name might have been meant as a reference to
+ * some not-yet-in-scope CTE. The bare "does not exist" message
+ * has proven remarkably unhelpful for figuring out such problems,
+ * so we take pains to offer a specific hint.
+ */
+ if (isFutureCTE(pstate, relation->relname))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_TABLE),
+ errmsg("relation \"%s\" does not exist",
+ relation->relname),
+ errdetail("There is a WITH item named \"%s\", but it cannot be referenced from this part of the query.",
+ relation->relname),
+ errhint("Use WITH RECURSIVE, or re-order the WITH items to remove forward references.")));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_TABLE),
+ relation->schemaname ?
+ errmsg("relation \"%s.%s\" does not exist", relation->schemaname, relation->relname) :
+ errmsg("relation \"%s\" does not exist", relation->relname)));
+}
+
/*
* Open a table during parse analysis
*
@@ -1436,35 +1459,7 @@ parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
rel = table_openrv_extended(relation, lockmode, true);
if (rel == NULL)
- {
- if (relation->schemaname)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_TABLE),
- errmsg("relation \"%s.%s\" does not exist",
- relation->schemaname, relation->relname)));
- else
- {
- /*
- * An unqualified name might have been meant as a reference to
- * some not-yet-in-scope CTE. The bare "does not exist" message
- * has proven remarkably unhelpful for figuring out such problems,
- * so we take pains to offer a specific hint.
- */
- if (isFutureCTE(pstate, relation->relname))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_TABLE),
- errmsg("relation \"%s\" does not exist",
- relation->relname),
- errdetail("There is a WITH item named \"%s\", but it cannot be referenced from this part of the query.",
- relation->relname),
- errhint("Use WITH RECURSIVE, or re-order the WITH items to remove forward references.")));
- else
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_TABLE),
- errmsg("relation \"%s\" does not exist",
- relation->relname)));
- }
- }
+ errorMissingRelation(pstate, relation);
cancel_parser_errposition_callback(&pcbstate);
return rel;
}
@@ -3971,3 +3966,14 @@ getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
return perminfo;
}
+
+
+/*
+ * Ignore absurd suggestions (e.g., mostly different characters).
+ * Having MAX_FUZZY_DISTANCE = 3, `abc` and `xyz` have a levenshtein distance of 3 which falls under MAX_FUZZY_DISTANCE, but yet they're mostly different.
+ */
+static inline bool
+levenshtein_is_absurd(int distance, int matchlen)
+{
+ return distance > matchlen / 2;
+}
--
2.42.0