--- /dev/null
+.. change::
+ :tags: mssql, usecase
+ :tickets: 4966
+
+ The :meth:`.Dialect.get_indexes` will now reflect the filter definitions
+ for Partial Indexes / Filtered Indexes on the PostgreSQL and MSSQL
+ dialects. Pull request courtesy Ramon Williams.
rp = connection.execution_options(future_result=True).execute(
sql.text(
- "select ind.index_id, ind.is_unique, ind.name "
+ "select ind.index_id, ind.is_unique, ind.name, "
+ "ind.filter_definition "
"from sys.indexes as ind join sys.tables as tab on "
"ind.object_id=tab.object_id "
"join sys.schemas as sch on sch.schema_id=tab.schema_id "
"name": row["name"],
"unique": row["is_unique"] == 1,
"column_names": [],
+ "dialect_options": {"mssql_where": row["filter_definition"]},
}
rp = connection.execution_options(future_result=True).execute(
sql.text(
ix.indisunique, ix.indexprs, ix.indpred,
a.attname, a.attnum, c.conrelid, ix.indkey::varchar,
ix.indoption::varchar, i.reloptions, am.amname,
+ pg_get_expr(ix.indpred, ix.indrelid),
%s as indnkeyatts
FROM
pg_class t
idx_option,
options,
amname,
+ filter_definition,
indnkeyatts,
) = row
if amname and amname != "btree":
index["amname"] = amname
+ if filter_definition:
+ index["postgresql_where"] = filter_definition
+
result = []
for name, idx in indexes.items():
entry = {
entry.setdefault("dialect_options", {})[
"postgresql_using"
] = idx["amname"]
+ if "postgresql_where" in idx:
+ entry.setdefault("dialect_options", {})[
+ "postgresql_where"
+ ] = idx["postgresql_where"]
result.append(entry)
return result
eq_(set(list(t2.indexes)[0].columns), set([t2.c["x col"], t2.c.y]))
+ @testing.provide_metadata
+ def test_indexes_with_filtered(self):
+ metadata = self.metadata
+
+ t1 = Table(
+ "t",
+ metadata,
+ Column("id", Integer, primary_key=True),
+ Column("x", types.String(20)),
+ Column("y", types.Integer),
+ )
+ Index("idx_x", t1.c.x, mssql_where=t1.c.x == "test")
+ Index("idx_y", t1.c.y, mssql_where=t1.c.y >= 5)
+ metadata.create_all()
+ with testing.db.connect() as conn:
+ ind = testing.db.dialect.get_indexes(conn, "t", None)
+
+ filtered_indexes = []
+ for ix in ind:
+ if "dialect_options" in ix:
+ filtered_indexes.append(ix["dialect_options"]["mssql_where"])
+
+ eq_(sorted(filtered_indexes), ["([x]='test')", "([y]>=(5))"])
+
@testing.provide_metadata
def test_max_ident_in_varchar_not_present(self):
"""test [ticket:3504].
],
)
+ @testing.provide_metadata
+ def test_index_reflection_partial(self):
+ """Reflect the filter defintion on partial indexes
+ """
+
+ metadata = self.metadata
+
+ t1 = Table(
+ "table1",
+ metadata,
+ Column("id", Integer, primary_key=True),
+ Column("name", String(20)),
+ Column("x", Integer),
+ )
+ metadata.create_all()
+ with testing.db.connect().execution_options(autocommit=True) as conn:
+ conn.exec_driver_sql("create index idx1 on table1 ((id || name))")
+ conn.exec_driver_sql(
+ "CREATE INDEX idx2 ON table1 (id) WHERE name = 'test'"
+ )
+ conn.exec_driver_sql(
+ "CREATE INDEX idx3 ON table1 (id) WHERE x >= 5"
+ )
+ with testing.expect_warnings(
+ "Skipped unsupported reflection of "
+ "expression-based index idx1",
+ "Predicate of partial index idx2 ignored during reflection",
+ "Predicate of partial index idx3 ignored during reflection",
+ ):
+ ind = testing.db.dialect.get_indexes(conn, t1, None)
+
+ partial_definitions = []
+ for ix in ind:
+ if "dialect_options" in ix:
+ partial_definitions.append(
+ ix["dialect_options"]["postgresql_where"]
+ )
+
+ eq_(
+ sorted(partial_definitions),
+ ["((name)::text = 'test'::text)", "(x >= 5)"],
+ )
+
@testing.fails_if("postgresql < 8.3", "index ordering not supported")
@testing.provide_metadata
def test_index_reflection_with_sorting(self):