Skip to content

Add support for PostgreSQL index access methods (gist, spgist, brin, hash)#1053

Draft
dereuromark wants to merge 15 commits into5.nextfrom
feature/postgres-index-access-methods
Draft

Add support for PostgreSQL index access methods (gist, spgist, brin, hash)#1053
dereuromark wants to merge 15 commits into5.nextfrom
feature/postgres-index-access-methods

Conversation

@dereuromark
Copy link
Member

Summary

This PR adds support for additional PostgreSQL index access methods beyond the existing GIN support:

  • GiST (Generalized Search Tree) - for geometric data, range types, full-text search
  • SP-GiST (Space-Partitioned GiST) - for data with natural clustering (IP addresses, phone numbers)
  • BRIN (Block Range Index) - for large, naturally-ordered tables like time-series data
  • Hash - for simple equality comparisons

Additionally, this adds support for specifying operator classes (opclass) on index columns, which is useful for specialized index configurations like trigram similarity searches with gist_trgm_ops.

Changes

  • Add Index::GIN, Index::GIST, Index::SPGIST, Index::BRIN, Index::HASH constants
  • Add opclass option to Index class for specifying operator classes
  • Generalize PostgresAdapter::getIndexSqlDefinition() to support all access methods
  • Add comprehensive tests for each new index type
  • Update documentation with examples for all PostgreSQL index access methods

Usage

// GIN index for JSONB
$table->addIndex('tags', ['type' => 'gin']);

// GiST index with operator class for trigram search
$table->addIndex('name', [
    'type' => 'gist',
    'opclass' => ['name' => 'gist_trgm_ops'],
]);

// BRIN index for time-series data
$table->addIndex('recorded_at', ['type' => 'brin']);

// SP-GiST index for IP addresses
$table->addIndex('client_ip', ['type' => 'spgist']);

// Hash index for equality lookups
$table->addIndex('session_id', ['type' => 'hash']);

Refs cakephp/phinx#1823

dereuromark and others added 13 commits March 8, 2026 22:00
When a foreign key is added without an explicit name, the MysqlAdapter
and SqliteAdapter now generate a name following the pattern
'tablename_columnname' (e.g., 'articles_user_id' for a FK on the
user_id column in the articles table).

This matches the behavior of PostgresAdapter and SqlserverAdapter,
which already auto-generate FK names. This ensures constraint names
are always strings and prevents issues with constraint lookup methods
that expect string names.
Update the expected FK names in comparison files and schema dumps
to match the new auto-generated naming pattern (tablename_columnname).
The FK constraint name change from auto-generated (ibfk_N) to
explicit (table_column) also affects the implicit index MySQL
creates for FKs. Update comparison files to reflect the index
rename from user_id to articles_user_id.
With the FK naming changes, both the lock file and database have
the index named articles_user_id, so no diff is needed for this
index. Remove the index rename operations that were incorrectly
added.
* Add conflict resolution for auto-generated FK constraint names

When auto-generating FK constraint names, check if the name already
exists and append a counter suffix (_2, _3, etc.) if needed.

This prevents duplicate constraint name errors when multiple FKs
are created on the same columns with different references.

* Remove unused variable

* Truncate FK constraint names to max 128 characters

Limit auto-generated foreign key constraint names to 125 characters
to ensure the final name (including potential _XX counter suffix)
stays within 128 characters. This prevents identifier length errors
on databases with strict limits (MySQL: 64, PostgreSQL: 63).

* Use database-specific identifier length limits

- MySQL: 61 chars (64 limit - 3 for _XX suffix)
- PostgreSQL: 60 chars (63 limit - 3 for _XX suffix)
- SQL Server: 125 chars (128 limit - 3 for _XX suffix)
- SQLite: No limit needed

* Use IDENTIFIER_MAX_LENGTH class constant for clarity

Each adapter now defines its database-specific identifier length limit
as a class constant, making the code more self-documenting.
When generating migrations, the 'fixed' option could be set to null for
binary columns, which causes an error when running the migration because
Column::setFixed() expects a bool, not null.

Fixes #1046
Add upgrade documentation explaining the new auto-generated FK constraint
naming behavior introduced in #1041 and #1042, including:
- New consistent naming pattern across all adapters
- Potential impact on existing migrations with rollbacks
- Conflict resolution with counter suffixes
- Database-specific name length limits
Update bake templates and internal code to use the non-deprecated
setDelete() and setUpdate() methods instead of the deprecated
setOnDelete() and setOnUpdate() methods.

Fixes #1045
* Auto-generate foreign key constraint names when not provided

When a foreign key is added without an explicit name, the MysqlAdapter
and SqliteAdapter now generate a name following the pattern
'tablename_columnname' (e.g., 'articles_user_id' for a FK on the
user_id column in the articles table).

This matches the behavior of PostgresAdapter and SqlserverAdapter,
which already auto-generate FK names. This ensures constraint names
are always strings and prevents issues with constraint lookup methods
that expect string names.

* Update test comparison files for new FK naming convention

Update the expected FK names in comparison files and schema dumps
to match the new auto-generated naming pattern (tablename_columnname).

* Update test comparison files with index rename operations

The FK constraint name change from auto-generated (ibfk_N) to
explicit (table_column) also affects the implicit index MySQL
creates for FKs. Update comparison files to reflect the index
rename from user_id to articles_user_id.

* Remove unnecessary index operations from comparison file

With the FK naming changes, both the lock file and database have
the index named articles_user_id, so no diff is needed for this
index. Remove the index rename operations that were incorrectly
added.

* Add conflict resolution for auto-generated FK constraint names (#1042)

* Add conflict resolution for auto-generated FK constraint names

When auto-generating FK constraint names, check if the name already
exists and append a counter suffix (_2, _3, etc.) if needed.

This prevents duplicate constraint name errors when multiple FKs
are created on the same columns with different references.

* Remove unused variable

* Truncate FK constraint names to max 128 characters

Limit auto-generated foreign key constraint names to 125 characters
to ensure the final name (including potential _XX counter suffix)
stays within 128 characters. This prevents identifier length errors
on databases with strict limits (MySQL: 64, PostgreSQL: 63).

* Use database-specific identifier length limits

- MySQL: 61 chars (64 limit - 3 for _XX suffix)
- PostgreSQL: 60 chars (63 limit - 3 for _XX suffix)
- SQL Server: 125 chars (128 limit - 3 for _XX suffix)
- SQLite: No limit needed

* Use IDENTIFIER_MAX_LENGTH class constant for clarity

Each adapter now defines its database-specific identifier length limit
as a class constant, making the code more self-documenting.
Document foreign key constraint naming changes
The issue was a mismatch between CakePHP's LENGTH_LONG constant (4294967295)
and migrations' TEXT_LONG constant (2147483647).

When using `bake migration_diff`, CakePHP's schema reflection returns
LENGTH_LONG for LONGTEXT columns, but MysqlAdapter expected TEXT_LONG.

This fix:
1. MigrationHelper: Convert LENGTH_LONG to TEXT_LONG when generating migrations
2. MysqlAdapter: Accept both constants for backward compatibility with existing
   migrations that have the wrong value

Fixes #1029
…hash)

- Add Index constants for GIN, GIST, SPGIST, BRIN, and HASH access methods
- Add opclass option for specifying operator classes on index columns
- Generalize PostgresAdapter to support all access method types
- Add tests for each new index type
- Update documentation with examples for all PostgreSQL index types

Refs cakephp/phinx#1823
@dereuromark dereuromark changed the base branch from 5.x to 5.next March 17, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant