PG Bug reporting form <noreply@postgresql.org> writes:
> The function CompareIndexInfo() contains the code:
> /* ignore expressions at this stage */
> if ((info1->ii_IndexAttrNumbers[i] != InvalidAttrNumber) &&
> (attmap->attnums[info2->ii_IndexAttrNumbers[i] - 1] !=
> info1->ii_IndexAttrNumbers[i]))
> return false;
> where info1->ii_IndexAttrNumbers[i] is checked for InvalidAttrNumber
> (i. e. it's not an expression), but info2->ii_IndexAttrNumbers[i] is not.
Agreed, that's pretty broken, and it's not just that it risks an
invalid access. I don't think this reliably rejects cases where
one index has an expression and the other doesn't. Even if it does
work, it's way too complicated to convince oneself that that's
rejected. I think for clarity we should code it as attached.
regards, tom lane
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 716de171a4..3d5adab2c5 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -2559,7 +2559,7 @@ CompareIndexInfo(const IndexInfo *info1, const IndexInfo *info2,
/*
* and columns match through the attribute map (actual attribute numbers
- * might differ!) Note that this implies that index columns that are
+ * might differ!) Note that this checks that index columns that are
* expressions appear in the same positions. We will next compare the
* expressions themselves.
*/
@@ -2568,13 +2568,22 @@ CompareIndexInfo(const IndexInfo *info1, const IndexInfo *info2,
if (attmap->maplen < info2->ii_IndexAttrNumbers[i])
elog(ERROR, "incorrect attribute map");
- /* ignore expressions at this stage */
- if ((info1->ii_IndexAttrNumbers[i] != InvalidAttrNumber) &&
- (attmap->attnums[info2->ii_IndexAttrNumbers[i] - 1] !=
- info1->ii_IndexAttrNumbers[i]))
- return false;
+ /* ignore expressions for now (but check their collation/opfamily) */
+ if (!(info1->ii_IndexAttrNumbers[i] == InvalidAttrNumber &&
+ info2->ii_IndexAttrNumbers[i] == InvalidAttrNumber))
+ {
+ /* fail if just one index has an expression in this column */
+ if (info1->ii_IndexAttrNumbers[i] == InvalidAttrNumber ||
+ info2->ii_IndexAttrNumbers[i] == InvalidAttrNumber)
+ return false;
+
+ /* both are columns, so check for match after mapping */
+ if (attmap->attnums[info2->ii_IndexAttrNumbers[i] - 1] !=
+ info1->ii_IndexAttrNumbers[i])
+ return false;
+ }
- /* collation and opfamily is not valid for including columns */
+ /* collation and opfamily are not valid for included columns */
if (i >= info1->ii_NumIndexKeyAttrs)
continue;