From: Mike Bayer Date: Wed, 20 Jul 2011 14:49:36 +0000 (-0400) Subject: - Added new "postgresql_ops" argument to X-Git-Tag: rel_0_7_2~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2d50f2807da38a4a0ecefc1a88ed4ab19e0e41c;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Added new "postgresql_ops" argument to Index, allows specification of PostgreSQL operator classes for indexed columns. [ticket:2198] Courtesy Filip Zyzniewski. --- diff --git a/CHANGES b/CHANGES index 74668f1e8c..d4804c1c18 100644 --- a/CHANGES +++ b/CHANGES @@ -128,6 +128,12 @@ CHANGES "retryable" condition. Only Oracle ORA-01033 implemented for now. [ticket:2201] +- postgresql + - Added new "postgresql_ops" argument to + Index, allows specification of PostgreSQL + operator classes for indexed columns. + [ticket:2198] Courtesy Filip Zyzniewski. + - mssql - Adjusted the pyodbc dialect such that bound values are passed as bytes and not unicode diff --git a/doc/build/core/schema.rst b/doc/build/core/schema.rst index dc1011bc15..1ddf494bb1 100644 --- a/doc/build/core/schema.rst +++ b/doc/build/core/schema.rst @@ -1100,6 +1100,7 @@ Constraints API .. autoclass:: UniqueConstraint :show-inheritance: +.. _schema_indexes: Indexes ------- diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py index 3193cde9ed..4c66ee91a5 100644 --- a/lib/sqlalchemy/dialects/postgresql/base.py +++ b/lib/sqlalchemy/dialects/postgresql/base.py @@ -75,14 +75,43 @@ use the :meth:`._UpdateBase.returning` method on a per-statement basis:: where(table.c.name=='foo') print result.fetchall() -Indexes -------- -PostgreSQL supports partial indexes. To create them pass a postgresql_where -option to the Index constructor:: +.. _postgresql_indexes: + +Postgresql-Specific Index Options +--------------------------------- + +Several extensions to the :class:`.Index` construct are available, specific +to the PostgreSQL dialect. + +Partial Indexes +^^^^^^^^^^^^^^^^ + +Partial indexes add criterion to the index definition so that the index is +applied to a subset of rows. These can be specified on :class:`.Index` +using the ``postgresql_where`` keyword argument:: Index('my_index', my_table.c.id, postgresql_where=tbl.c.value > 10) +Operator Classes +^^^^^^^^^^^^^^^^^ + +PostgreSQL allows the specification of an *operator class* for each column of +an index (see http://www.postgresql.org/docs/8.3/interactive/indexes-opclass.html). +The :class:`.Index` construct allows these to be specified via the ``postgresql_ops`` +keyword argument (new as of SQLAlchemy 0.7.2):: + + Index('my_index', my_table.c.id, my_table.c.data, + postgresql_ops={ + 'data': 'text_pattern_ops', + 'id': 'int4_ops' + }) + +Note that the keys in the ``postgresql_ops`` dictionary are the "key" name of +the :class:`.Column`, i.e. the name used to access it from the ``.c`` collection +of :class:`.Table`, which can be configured to be different than the actual +name of the column as expressed in the database. + """ import re @@ -570,12 +599,17 @@ class PGDDLCompiler(compiler.DDLCompiler): text = "CREATE " if index.unique: text += "UNIQUE " + ops = index.kwargs.get('postgresql_ops', {}) text += "INDEX %s ON %s (%s)" \ - % (preparer.quote( - self._index_identifier(index.name), index.quote), - preparer.format_table(index.table), - ', '.join([preparer.format_column(c) - for c in index.columns])) + % ( + preparer.quote( + self._index_identifier(index.name), index.quote), + preparer.format_table(index.table), + ', '.join([ + preparer.format_column(c) + + (c.key in ops and (' ' + ops[c.key]) or '') + for c in index.columns]) + ) if "postgres_where" in index.kwargs: whereclause = index.kwargs['postgres_where'] diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 7323a5657a..1763dc484d 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -2079,7 +2079,13 @@ class Index(ColumnCollectionMixin, SchemaItem): Defines a composite (one or more column) INDEX. For a no-frills, single column index, adding ``index=True`` to the ``Column`` definition is - a shorthand equivalent for an unnamed, single column Index. + a shorthand equivalent for an unnamed, single column :class:`.Index`. + + See also: + + :ref:`schema_indexes` - General information on :class:`.Index`. + + :ref:`postgresql_indexes` - PostgreSQL-specific options available for the :class:`.Index` construct. """ __visit_name__ = 'index' diff --git a/test/dialect/test_postgresql.py b/test/dialect/test_postgresql.py index 70730983cc..4dffa04153 100644 --- a/test/dialect/test_postgresql.py +++ b/test/dialect/test_postgresql.py @@ -152,6 +152,28 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): "WHERE data > 'a' AND data < 'b''s'", dialect=postgresql.dialect()) + def test_create_index_with_ops(self): + m = MetaData() + tbl = Table('testtbl', m, + Column('data', String), + Column('data2', key='d2', Integer)) + + idx = Index('test_idx1', tbl.c.data, + postgresql_ops={'data': 'text_pattern_ops'}) + + idx2 = Index('test_idx2', tbl.c.data, tbl.c.d2, + postgresql_ops={'data': 'text_pattern_ops', + 'd2': 'int4_ops'}) + + self.assert_compile(schema.CreateIndex(idx), + 'CREATE INDEX test_idx1 ON testtbl ' + '(data text_pattern_ops)', + dialect=postgresql.dialect()) + self.assert_compile(schema.CreateIndex(idx2), + 'CREATE INDEX test_idx2 ON testtbl ' + '(data text_pattern_ops, data2 int4_ops)', + dialect=postgresql.dialect()) + @testing.uses_deprecated(r".*'postgres_where' argument has been " "renamed.*") def test_old_create_partial_index(self):