--- /dev/null
+.. change::
+ :tags: bug, postgresql
+ :tickets: 5205
+
+ Fixed issue where a "covering" index, e.g. those which have an INCLUDE
+ clause, would be reflected including all the columns in INCLUDE clause as
+ regular columns. A warning is now emitted if these additional columns are
+ detected indicating that they are currently ignored. Note that full
+ support for "covering" indexes is part of :ticket:`4458`. Pull request
+ courtesy Marat Sharafutdinov.
i.relname as relname,
ix.indisunique, ix.indexprs, ix.indpred,
a.attname, a.attnum, NULL, ix.indkey%s,
- %s, %s, am.amname
+ %s, %s, am.amname,
+ NULL as indnkeyatts
FROM
pg_class t
join pg_index ix on t.oid = ix.indrelid
i.relname as relname,
ix.indisunique, ix.indexprs, ix.indpred,
a.attname, a.attnum, c.conrelid, ix.indkey::varchar,
- ix.indoption::varchar, i.reloptions, am.amname
+ ix.indoption::varchar, i.reloptions, am.amname,
+ %s as indnkeyatts
FROM
pg_class t
join pg_index ix on t.oid = ix.indrelid
ORDER BY
t.relname,
i.relname
- """
+ """ % (
+ "ix.indnkeyatts"
+ if self.server_version_info >= (11, 0)
+ else "NULL",
+ )
t = sql.text(IDX_SQL).columns(
relname=sqltypes.Unicode, attname=sqltypes.Unicode
idx_option,
options,
amname,
+ indnkeyatts,
) = row
if expr:
if col is not None:
index["cols"][col_num] = col
if not has_idx:
- index["key"] = [int(k.strip()) for k in idx_key.split()]
+ idx_keys = idx_key.split()
+ # "The number of key columns in the index, not counting any
+ # included columns, which are merely stored and do not
+ # participate in the index semantics"
+ if indnkeyatts and idx_keys[indnkeyatts:]:
+ util.warn(
+ "INCLUDE columns for covering index %s "
+ "ignored during reflection" % (idx_name,)
+ )
+ idx_keys = idx_keys[:indnkeyatts]
+
+ index["key"] = [int(k.strip()) for k in idx_keys]
# (new in pg 8.3)
# "pg_index.indoption" is list of ints, one per column/expr.
"gin",
)
+ @testing.skip_if("postgresql < 11.0", "indnkeyatts not supported")
+ @testing.provide_metadata
+ def test_index_reflection_with_include(self):
+ """reflect indexes with include set"""
+
+ metadata = self.metadata
+
+ Table(
+ "t",
+ metadata,
+ Column("id", Integer, primary_key=True),
+ Column("x", ARRAY(Integer)),
+ Column("name", String(20)),
+ )
+ metadata.create_all()
+ with testing.db.connect() as conn:
+ conn.execute("CREATE INDEX idx1 ON t (x) INCLUDE (name)")
+
+ # prior to #5205, this would return:
+ # [{'column_names': ['x', 'name'],
+ # 'name': 'idx1', 'unique': False}]
+
+ with testing.expect_warnings(
+ "INCLUDE columns for "
+ "covering index idx1 ignored during reflection"
+ ):
+ ind = testing.db.dialect.get_indexes(conn, "t", None)
+ eq_(
+ ind,
+ [{"unique": False, "column_names": ["x"], "name": "idx1"}],
+ )
+
@testing.provide_metadata
def test_foreign_key_option_inspection(self):
metadata = self.metadata