]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Added new "postgresql_ops" argument to
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 20 Jul 2011 14:49:36 +0000 (10:49 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 20 Jul 2011 14:49:36 +0000 (10:49 -0400)
    Index, allows specification of PostgreSQL
    operator classes for indexed columns.
    [ticket:2198]  Courtesy Filip Zyzniewski.

CHANGES
doc/build/core/schema.rst
lib/sqlalchemy/dialects/postgresql/base.py
lib/sqlalchemy/schema.py
test/dialect/test_postgresql.py

diff --git a/CHANGES b/CHANGES
index 74668f1e8cd651f2d514f9184f436e64bcd16497..d4804c1c18e6eddf78d50e26e33f079262045f15 100644 (file)
--- 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
index dc1011bc15543b85d15a4177427700933ea7e21d..1ddf494bb164c9e9a6e689a01c2bffefea261faa 100644 (file)
@@ -1100,6 +1100,7 @@ Constraints API
 .. autoclass:: UniqueConstraint
     :show-inheritance:
 
+.. _schema_indexes:
 
 Indexes
 -------
index 3193cde9ed6077f737bc1c7a8a294b393ba3c813..4c66ee91a572729ae0f0e3be9153a90c4f1ee656 100644 (file)
@@ -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']
index 7323a5657ae00fe0da3c72b03da9a2101b787d14..1763dc484d164233c8deab61587016312baba163 100644 (file)
@@ -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'
index 70730983cc49c1c41d00583d76ec39b9124db664..4dffa04153acdef763604a97d94b2c9c306583d9 100644 (file)
@@ -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):