--- /dev/null
+.. change::
+ :tags: bug, postgresql
+ :tickets: 9615
+
+ Fixed issue that prevented reflection of expression based indexes
+ with long expressions in PostgreSQL. The expression where erroneously
+ truncated to the identifier length (that's 63 bytes by default).
select(
pg_catalog.pg_class.c.relname,
pg_catalog.pg_constraint.c.conname,
+ # NOTE: avoid calling pg_get_constraintdef when not needed
+ # to speed up the query
sql.case(
(
pg_catalog.pg_constraint.c.oid.is_not(None),
idx_sq.c.indexrelid, idx_sq.c.ord + 1, True
),
),
- else_=pg_catalog.pg_attribute.c.attname,
+ # NOTE: need to cast this since attname is of type "name"
+ # that's limited to 63 bytes, while pg_get_indexdef
+ # returns "text" so it may get cut
+ else_=sql.cast(pg_catalog.pg_attribute.c.attname, TEXT()),
).label("element"),
(idx_sq.c.attnum == 0).label("is_expr"),
)
pg_catalog.pg_index.c.indoption,
pg_class_index.c.reloptions,
pg_catalog.pg_am.c.amname,
+ # NOTE: pg_get_expr is very fast so this case has almost no
+ # performance impact
sql.case(
- # pg_get_expr is very fast so this case has almost no
- # performance impact
(
pg_catalog.pg_index.c.indpred.is_not(None),
pg_catalog.pg_get_expr(
pg_catalog.pg_index.c.indrelid,
),
),
- else_=sql.null(),
+ else_=None,
).label("filter_definition"),
indnkeyatts,
cols_sq.c.elements,
select(
pg_catalog.pg_class.c.relname,
pg_catalog.pg_constraint.c.conname,
+ # NOTE: avoid calling pg_get_constraintdef when not needed
+ # to speed up the query
sql.case(
(
pg_catalog.pg_constraint.c.oid.is_not(None),
)
Index("t_idx", func.lower(t.c.x), t.c.z, func.lower(t.c.y))
-
+ long_str = "long string " * 100
+ Index("t_idx_long", func.coalesce(t.c.x, long_str))
Index("t_idx_2", t.c.x)
metadata.create_all(connection)
completeIndex(expected[0])
- class filtering_str(str):
+ class lower_index_str(str):
def __eq__(self, other):
# test that lower and x or y are in the string
return "lower" in other and ("x" in other or "y" in other)
+ class coalesce_index_str(str):
+ def __eq__(self, other):
+ # test that coalesce and the string is in other
+ return "coalesce" in other.lower() and long_str in other
+
if testing.requires.reflect_indexes_with_expressions.enabled:
expr_index = {
"name": "t_idx",
"column_names": [None, "z", None],
"expressions": [
- filtering_str("lower(x)"),
+ lower_index_str("lower(x)"),
"z",
- filtering_str("lower(y)"),
+ lower_index_str("lower(y)"),
],
"unique": False,
}
completeIndex(expr_index)
expected.insert(0, expr_index)
+
+ expr_index_long = {
+ "name": "t_idx_long",
+ "column_names": [None],
+ "expressions": [
+ coalesce_index_str(f"coalesce(x, '{long_str}')")
+ ],
+ "unique": False,
+ }
+ completeIndex(expr_index_long)
+ expected.append(expr_index_long)
+
eq_(insp.get_indexes("t"), expected)
m2 = MetaData()
t2 = Table("t", m2, autoload_with=connection)